home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 11 / CU Amiga Magazine's Super CD-ROM 11 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-06].iso / cucd / graphics / mpimage / si / savempi.c < prev    next >
C/C++ Source or Header  |  1997-03-04  |  73KB  |  3,010 lines

  1. // MPImage - Amiga Image Conversion
  2. // Copyright (C) © 1996 Mark John Paddock
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; either version 2 of the License, or
  7. // any later version.
  8.  
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. // GNU General Public License for more details.
  13.  
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program; if not, write to the Free Software
  16. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. // mark@topic.demon.co.uk
  19. // mpaddock@cix.compulink.co.uk
  20.  
  21. #include "mpimage.h"
  22.  
  23. // Following explains(?) the palette choices
  24.  
  25. //   0 = x00 = b00000000
  26. //  85 = x55 = b01010101
  27. // 170 = xaa = b10101010
  28. // 255 = xff = b11111111
  29.  
  30. //   0 = x00 = o000 = b00000000
  31. //  36 = x24 = o111 = b00100100
  32. //  73 = x49 = o222 = b01001001
  33. // 109 = x6d = o333 = b01101101
  34. // 146 = x92 = o444 = b10010010
  35. // 182 = xb6 = o555 = b10110110
  36. // 219 = xdb = o666 = b11011011
  37. // 255 = xff = o777 = b11111111
  38.  
  39. //   0 = x00 = b00000000
  40. //  17 = x11 = b00010001
  41. //  34 = x22 = b00100010
  42. //  51 = x33 = b00110011
  43. //  68 = x44 = b01000100
  44. //  85 = x55 = b01010101
  45. // 102 = x66 = b01100110
  46. // 119 = x77 = b01110111
  47. // 136 = x88 = b10001000
  48. // 153 = x99 = b10011001
  49. // 170 = xaa = b10101010
  50. // 187 = xbb = b10111011
  51. // 204 = xcc = b11001100
  52. // 221 = xdd = b11011101
  53. // 238 = xee = b11101110
  54. // 255 = xff = b11111111 
  55.  
  56. // 16 grey shade palette
  57. UBYTE BW16_Palette[16][3] = {
  58.     0,0,0,
  59.     17,17,17,
  60.     34,34,34,
  61.     51,51,51,
  62.     68,68,68,
  63.     85,85,85,
  64.     102,102,102,
  65.     119,119,119,
  66.     136,136,136,
  67.     153,153,153,
  68.     170,170,170,
  69.     187,187,187,
  70.     204,204,204,
  71.     221,221,221,
  72.     238,238,238,
  73.     255,255,255
  74. };
  75.  
  76. // 256 grey shade palette
  77. UBYTE BW256_Palette[256][3] = {
  78.     0,0,0,
  79.     1,1,1,
  80.     2,2,2,
  81.     3,3,3,
  82.     4,4,4,
  83.     5,5,5,
  84.     6,6,6,
  85.     7,7,7,
  86.     8,8,8,
  87.     9,9,9,
  88.     10,10,10,
  89.     11,11,11,
  90.     12,12,12,
  91.     13,13,13,
  92.     14,14,14,
  93.     15,15,15,
  94.     16,16,16,
  95.     17,17,17,
  96.     18,18,18,
  97.     19,19,19,
  98.     20,20,20,
  99.     21,21,21,
  100.     22,22,22,
  101.     23,23,23,
  102.     24,24,24,
  103.     25,25,25,
  104.     26,26,26,
  105.     27,27,27,
  106.     28,28,28,
  107.     29,29,29,
  108.     30,30,30,
  109.     31,31,31,
  110.     32,32,32,
  111.     33,33,33,
  112.     34,34,34,
  113.     35,35,35,
  114.     36,36,36,
  115.     37,37,37,
  116.     38,38,38,
  117.     39,39,39,
  118.     40,40,40,
  119.     41,41,41,
  120.     42,42,42,
  121.     43,43,43,
  122.     44,44,44,
  123.     45,45,45,
  124.     46,46,46,
  125.     47,47,47,
  126.     48,48,48,
  127.     49,49,49,
  128.     50,50,50,
  129.     51,51,51,
  130.     52,52,52,
  131.     53,53,53,
  132.     54,54,54,
  133.     55,55,55,
  134.     56,56,56,
  135.     57,57,57,
  136.     58,58,58,
  137.     59,59,59,
  138.     60,60,60,
  139.     61,61,61,
  140.     62,62,62,
  141.     63,63,63,
  142.     64,64,64,
  143.     65,65,65,
  144.     66,66,66,
  145.     67,67,67,
  146.     68,68,68,
  147.     69,69,69,
  148.     70,70,70,
  149.     71,71,71,
  150.     72,72,72,
  151.     73,73,73,
  152.     74,74,74,
  153.     75,75,75,
  154.     76,76,76,
  155.     77,77,77,
  156.     78,78,78,
  157.     79,79,79,
  158.     80,80,80,
  159.     81,81,81,
  160.     82,82,82,
  161.     83,83,83,
  162.     84,84,84,
  163.     85,85,85,
  164.     86,86,86,
  165.     87,87,87,
  166.     88,88,88,
  167.     89,89,89,
  168.     90,90,90,
  169.     91,91,91,
  170.     92,92,92,
  171.     93,93,93,
  172.     94,94,94,
  173.     95,95,95,
  174.     96,96,96,
  175.     97,97,97,
  176.     98,98,98,
  177.     99,99,99,
  178.     100,100,100,
  179.     101,101,101,
  180.     102,102,102,
  181.     103,103,103,
  182.     104,104,104,
  183.     105,105,105,
  184.     106,106,106,
  185.     107,107,107,
  186.     108,108,108,
  187.     109,109,109,
  188.     110,110,110,
  189.     111,111,111,
  190.     112,112,112,
  191.     113,113,113,
  192.     114,114,114,
  193.     115,115,115,
  194.     116,116,116,
  195.     117,117,117,
  196.     118,118,118,
  197.     119,119,119,
  198.     120,120,120,
  199.     121,121,121,
  200.     122,122,122,
  201.     123,123,123,
  202.     124,124,124,
  203.     125,125,125,
  204.     126,126,126,
  205.     127,127,127,
  206.     128,128,128,
  207.     129,129,129,
  208.     130,130,130,
  209.     131,131,131,
  210.     132,132,132,
  211.     133,133,133,
  212.     134,134,134,
  213.     135,135,135,
  214.     136,136,136,
  215.     137,137,137,
  216.     138,138,138,
  217.     139,139,139,
  218.     140,140,140,
  219.     141,141,141,
  220.     142,142,142,
  221.     143,143,143,
  222.     144,144,144,
  223.     145,145,145,
  224.     146,146,146,
  225.     147,147,147,
  226.     148,148,148,
  227.     149,149,149,
  228.     150,150,150,
  229.     151,151,151,
  230.     152,152,152,
  231.     153,153,153,
  232.     154,154,154,
  233.     155,155,155,
  234.     156,156,156,
  235.     157,157,157,
  236.     158,158,158,
  237.     159,159,159,
  238.     160,160,160,
  239.     161,161,161,
  240.     162,162,162,
  241.     163,163,163,
  242.     164,164,164,
  243.     165,165,165,
  244.     166,166,166,
  245.     167,167,167,
  246.     168,168,168,
  247.     169,169,169,
  248.     170,170,170,
  249.     171,171,171,
  250.     172,172,172,
  251.     173,173,173,
  252.     174,174,174,
  253.     175,175,175,
  254.     176,176,176,
  255.     177,177,177,
  256.     178,178,178,
  257.     179,179,179,
  258.     180,180,180,
  259.     181,181,181,
  260.     182,182,182,
  261.     183,183,183,
  262.     184,184,184,
  263.     185,185,185,
  264.     186,186,186,
  265.     187,187,187,
  266.     188,188,188,
  267.     189,189,189,
  268.     190,190,190,
  269.     191,191,191,
  270.     192,192,192,
  271.     193,193,193,
  272.     194,194,194,
  273.     195,195,195,
  274.     196,196,196,
  275.     197,197,197,
  276.     198,198,198,
  277.     199,199,199,
  278.     200,200,200,
  279.     201,201,201,
  280.     202,202,202,
  281.     203,203,203,
  282.     204,204,204,
  283.     205,205,205,
  284.     206,206,206,
  285.     207,207,207,
  286.     208,208,208,
  287.     209,209,209,
  288.     210,210,210,
  289.     211,211,211,
  290.     212,212,212,
  291.     213,213,213,
  292.     214,214,214,
  293.     215,215,215,
  294.     216,216,216,
  295.     217,217,217,
  296.     218,218,218,
  297.     219,219,219,
  298.     220,220,220,
  299.     221,221,221,
  300.     222,222,222,
  301.     223,223,223,
  302.     224,224,224,
  303.     225,225,225,
  304.     226,226,226,
  305.     227,227,227,
  306.     228,228,228,
  307.     229,229,229,
  308.     230,230,230,
  309.     231,231,231,
  310.     232,232,232,
  311.     233,233,233,
  312.     234,234,234,
  313.     235,235,235,
  314.     236,236,236,
  315.     237,237,237,
  316.     238,238,238,
  317.     239,239,239,
  318.     240,240,240,
  319.     241,241,241,
  320.     242,242,242,
  321.     243,243,243,
  322.     244,244,244,
  323.     245,245,245,
  324.     246,246,246,
  325.     247,247,247,
  326.     248,248,248,
  327.     249,249,249,
  328.     250,250,250,
  329.     251,251,251,
  330.     252,252,252,
  331.     253,253,253,
  332.     254,254,254,
  333.     255,255,255,
  334. };
  335.  
  336. // HAM6 base palette
  337. // note 3 extra entries based on changing r,g or b using HAM stuff
  338. static UBYTE HAM6_Palette[19][3] = {
  339.     0,0,0,
  340.     0,0,170,
  341.     0,85,0,
  342.     0,85,170,
  343.     0,170,0,
  344.     0,170,170,
  345.     0,255,0,
  346.     0,255,170,
  347.     170,0,0,
  348.     170,0,170,
  349.     170,85,0,
  350.     170,85,170,
  351.     170,170,0,
  352.     170,170,170,
  353.     170,255,0,
  354.     255,255,255,
  355.     0,0,0,    // r
  356.     0,0,0,    // g
  357.     0,0,0,    // b
  358. };
  359.  
  360. // HAM8 base palette
  361. // note 3 extra entries based on changing r,g or b using HAM stuff
  362. UBYTE HAM8_Palette[67][3] = {
  363.     0,0,0,
  364.     0,0,170,
  365.     0,36,0,
  366.     0,36,170,
  367.     0,73,0,
  368.     0,73,170,
  369.     0,109,0,
  370.     0,109,170,
  371.     0,146,0,
  372.     0,146,170,
  373.     0,182,0,
  374.     0,182,170,
  375.     0,219,0,
  376.     0,219,170,
  377.     0,255,0,
  378.     0,255,170,
  379.     85,0,0,
  380.     85,0,170,
  381.     85,36,0,
  382.     85,36,170,
  383.     85,73,0,
  384.     85,73,170,
  385.     85,109,0,
  386.     85,109,170,
  387.     85,146,0,
  388.     85,146,170,
  389.     85,182,0,
  390.     85,182,170,
  391.     85,219,0,
  392.     85,219,170,
  393.     85,255,0,
  394.     85,255,170,
  395.     170,0,0,
  396.     170,0,170,
  397.     170,36,0,
  398.     170,36,170,
  399.     170,73,0,
  400.     170,73,170,
  401.     170,109,0,
  402.     170,109,170,
  403.     170,146,0,
  404.     170,146,170,
  405.     170,182,0,
  406.     170,182,170,
  407.     170,219,0,
  408.     170,219,170,
  409.     170,255,0,
  410.     170,255,170,
  411.     255,0,0,
  412.     255,0,170,
  413.     255,36,0,
  414.     255,36,170,
  415.     255,73,0,
  416.     255,73,170,
  417.     255,109,0,
  418.     255,109,170,
  419.     255,146,0,
  420.     255,146,170,
  421.     255,182,0,
  422.     255,182,170,
  423.     255,219,0,
  424.     255,219,170,
  425.     255,255,0,
  426.     255,255,255,
  427.     0,0,0,    // r
  428.     0,0,0,    // g
  429.     0,0,0,    // b
  430. };
  431.  
  432. UBYTE MyPalette[256][3];
  433.  
  434. UBYTE DefGreyMap[256] = {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
  435.                                   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
  436.                                   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
  437.                                   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
  438.                                   64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  439.                                   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
  440.                                   96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
  441.                                  112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
  442.                                  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
  443.                                  144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
  444.                                  160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
  445.                                  176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
  446.                                  192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
  447.                                  208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
  448.                                  224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
  449.                                  240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
  450.                                 };
  451.  
  452. BOOL __asm __saveds SaveMPImageA(register __a0 const UBYTE *file,
  453.                                 register __a1 UBYTE *red, register __a2 UBYTE *green,register __a3 UBYTE *blue,
  454.                                 register __d0 UWORD width, register __d1 UWORD height,
  455.                                 register __a5 struct TagItem *TagList);
  456.  
  457. extern UWORD MedianCut(UWORD Hist[],UBYTE ColMap[][3], int maxcubes, UWORD HistPtr[]);
  458. extern UWORD MedHam6(UWORD Hist[],UBYTE ColMap[][3], int maxcubes, UWORD HistPtr[]);
  459.  
  460. static ULONG LoadPalette(UBYTE *filename);
  461. static BOOL ComputePalette(UWORD Depth,UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue);
  462. static BOOL ComputePal12(UWORD Depth,UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue);
  463. static BOOL ComputePalEHB(UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue);
  464. static ULONG GetMode(UWORD height, UWORD width, UWORD depth, ULONG camg, ULONG flags, const UBYTE * filename);
  465. static BOOL SaveBW16(const UBYTE *FileName,USHORT width,USHORT height,
  466.                   UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg, UBYTE *GreyMap, BOOL Linear, struct BitMap *NewBitMap);
  467. static BOOL SaveBW256(const UBYTE *FileName,USHORT width,USHORT height,
  468.                   UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg, UBYTE *GreyMap, BOOL Linear, struct BitMap *NewBitMap);
  469. static BOOL SaveHAM6(const UBYTE *FileName,USHORT width,USHORT height,
  470.                   UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg,struct BitMap *NewBitMap);
  471. static BOOL SaveHAM8(const UBYTE *FileName,USHORT width,USHORT height,
  472.                   UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg,struct BitMap *NewBitMap);
  473. static BOOL Save24(const UBYTE *FileName,USHORT width,USHORT height,
  474.                   UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg);
  475. static BOOL SavePPM(const UBYTE *FileName,USHORT width,USHORT height,
  476.                   UBYTE *red, UBYTE *green, UBYTE *blue,UWORD jpeg);
  477. static BOOL SaveColour(const UBYTE *FileName,USHORT width,USHORT height,
  478.                   UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg, ULONG numcols,struct BitMap *NewBitMap);
  479. static BOOL SaveColour12(const UBYTE *FileName,USHORT width,USHORT height,
  480.                   UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg, ULONG numcols,struct BitMap *NewBitMap);
  481. static BOOL SaveEHB(const UBYTE *FileName,USHORT width,USHORT height,
  482.                   UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg,struct BitMap *NewBitMap);
  483. static BOOL SaveDCTV(const UBYTE *FileName,USHORT width,USHORT height,
  484.                   UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg,BOOL dctv4,struct BitMap *NewBitMap);
  485. static LONG mysaveilbm(struct ILBMInfo *ilbm,
  486.         struct BitMap *bitmap, ULONG modeid,
  487.         WORD width, WORD height, WORD pagewidth, WORD pageheight,
  488.         UBYTE colortable[][3], UWORD count, UWORD bitspergun,
  489.                 WORD masking, WORD transparentColor,
  490.         struct Chunk *chunklist1, struct Chunk *chunklist2,
  491.         UBYTE *filename,int Depth);
  492.  
  493. // Properties for IFF read
  494. static LONG props[] = { ID_ILBM,    ID_BMHD,
  495.                         ID_ILBM,    ID_CAMG,
  496.                         ID_ILBM, ID_CMAP,
  497.                         TAG_DONE };
  498. static LONG stops[] = {    ID_ILBM,    ID_BODY,
  499.                         TAG_DONE };
  500. static LONG nowt[] = { TAG_DONE };
  501.  
  502. static void
  503. CopyNewPal(UBYTE OldPal[][3],UBYTE *NewPal,ULONG Cols) {
  504.     int i;
  505.     for (i=0; i<Cols; ++i) {
  506.         NewPal[i] = OldPal[i][0];
  507.         NewPal[i+256] = OldPal[i][1];
  508.         NewPal[i+512] = OldPal[i][2];
  509.     }
  510. }
  511.  
  512. static void
  513. CopyOldPal(UBYTE *NewPal,UBYTE OldPal[][3],ULONG Cols) {
  514.     int i;
  515.     for (i=0; i<Cols; ++i) {
  516.         OldPal[i][0] = NewPal[i];
  517.         OldPal[i][1] = NewPal[i+256];
  518.         OldPal[i][2] = NewPal[i+512];
  519.     }
  520. }
  521.  
  522. /****** MPImage.library/SaveMPImageA *****************************************
  523. *
  524. *   NAME   
  525. *  SaveMPImageA -- Save an image in various formats. (V3)
  526. *  SaveMPIMage -- Varargs version of SaveMPImageA (V3)
  527. *
  528. *   SYNOPSIS
  529. *  succ = SaveMPImageA( file,red,green,blue,width,height,taglist)
  530. *  D0                   A0   A1  A2    A3   D0    D1     A5
  531. *
  532. *  BOOL SaveMPImageA( UBYTE *,UBYTE *,UBYTE *,UBYTE *,
  533. *                                   UWORD,UWORD,struct TagItem *);
  534. *
  535. *  succ = SaveMPImage( file,red,green,blue,width,height,Tag1, ...)
  536. *
  537. *  BOOL SaveMPImage( UBYTE *,UBYTE *,UBYTE *,UBYTE *,
  538. *                                   UWORD,UWORD,ULONG,...);
  539. *
  540. *   FUNCTION
  541. *  Saves/displays an image held in chunky buffers.
  542. *
  543. *   INPUTS
  544. *  file    - filename to save file as. If NULL or "" then image is
  545. *            displayed on a custom screen, or returned in BitMap (V7.0)
  546. *  red     - red chunky input.
  547. *  green   - green chunky input.
  548. *  blue    - blue chunky input.
  549. *  width   - width of chunky buffers
  550. *  height  - height of chunky buffers.
  551. *  taglist - pointer to TagItem array.
  552. *
  553. *  Tags are:
  554. *
  555. *  MPIS_MODE   - Data is ULONG CAMG of output IFF file/screen EHB and HAM
  556. *                will be added if required. If not supplied then
  557. *                MPIS_MODENAME will be used. If that is not supplied then
  558. *                a CAMG mode will be generated.
  559. *  MPIS_MODENAME - Data is char * mode name of CAMG of output. Invalid
  560. *                  names are ignored.
  561. *  MPIS_FORMAT - Data is char * specifying output format.
  562. *                Default is MPI_BW16. Values are:
  563. *                MPI_BW16   - "BW16"   - 16 colour ILBM grey scale.
  564. *                MPI_BW256  - "BW256"  - 256 colour ILBM grey scale.
  565. *                MPI_HAM6   - "HAM6"   - HAM6 with fixed (internal) palette.
  566. *                MPI_HAM6P  - "HAM6P"  - HAM6 with generated or supplied
  567. *                                        palette - see MPIS_PALETTE.
  568. *                MPI_HAM8   - "HAM8"   - HAM8 with fixed (internal) palette.
  569. *                MPI_HAM8P  - "HAM8P"  - HAM8 with generated or supplied
  570. *                                        palette - see MPIS_PALETTE.
  571. *                MPI_ILBM24 - "ILBM24" - 24 bit ILBM.
  572. *                MPI_PPM    - "PPM"    - P6 (or P5 if red,green and blue are
  573. *                                        the same).
  574. *                MPI_COLOUR - "COLOUR" - ILBM with generated or supplied
  575. *                                        palette - see MPIS_PALETTE.
  576. *                MPI_EHB    - "EHB"    - EHB with generated or supplied
  577. *                                        palette - see MPIS_PALETTE.
  578. *                MPI_JPEG   - "JPEG"   - JPEG see NOTES.
  579. *                MPI_PNM    - "PNG"    - PNG see NOTES.
  580. *                MPI_DCTV3  - "DCTV3"  - DCTV 3 bit plane format
  581. *                MPI_DCTV4  - "DCTV4"  - DCTV 4 bit plane format
  582. *  MPIS_PALETTE - Data is char * name of ILBM to load palette from.
  583. *  MPIS_COLOURS - Data is ULONG number of colours for MPI_COLOUR.
  584. *                 Default is is number of colours in MPIS_PALETTE if
  585. *                 supplied, otherwise 16. If greater than that from
  586. *                 MPIS_PALETTE then ignored.
  587. *  MPIS_12BIT   - Data is BOOL. If TRUE then use faster 12bit colour palette
  588. *                 generating algorithm for MPI_COLOUR and MPI_EHB. Default
  589. *                 is FALSE to use 18bit algorithm.
  590. *  MPIS_LINEAR  - Data is BOOL. If TRUE then for BW16/BW256 use linear
  591. *                 (not colour based) mapping. (V5.0)
  592. *  MPIS_GREYMAP - Data is UBYTE *. For BW16/BW256 palette map. Must point
  593. *                 to at least 16 of value 0 to 15 for BW16, 256 bytes of
  594. *                 0 to 255 for BW255. (V5.0)
  595. *                 Format is e.g. 0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1
  596. *                   Colour 0 will be black
  597. *                   Colour 1 will be white
  598. *                   etc.
  599. *                 This is the opposite to which you may expect!
  600. *  MPIS_OLDPALETTE - Palette to use (for HAMxP/COLOUR/EHB) (V7.0)
  601. *                    Data is UBYTE *, red in [0] to [255],
  602. *                                     green in [256] to [511]
  603. *                                     blue in [512] to [767]
  604. *  MPIS_NEWPALETTE - Palette used (for HAMx/COLOUR/EHB) (V7.0)
  605. *                    Data is UBYTE * (see MPIS_OLDPALETTE).
  606. *  MPIS_BITMAP  - BitMap to update (for BWxx/HAMxx/COLOUR/EHB/DCTVx) (V7.0)
  607. *                 Data is struct BitMap *
  608. *                 Image is not displayed/saved
  609. *
  610. *   RESULT
  611. *  error - 1 for success, 0 for failure.
  612. *          Use MPImageErrorMessage() to get error.
  613. *
  614. *   EXAMPLE
  615. *
  616. *   NOTES
  617. *  If MPIS_FORMAT is BW16 or BW256 and red,green and blue are the same then
  618. *  a more efficent algorithm is used.
  619. *
  620. *  When displaying on screen click in the top left and press a key to exit.
  621. *
  622. *  If file format is JPEG and env/mpimage/cjpeg is set (e.g. cjpeg "%s" "%s")
  623. *  then cjpeg is used.
  624. *
  625. *  If file format is PNG and env/mpimage/pnmtopng is set
  626. *  (e.g. 'pnmtopng "%s" >"%s"') then pnmtopng is used.
  627. *
  628. *   BUGS
  629. *  Does not work for images > 1024 wide (except PPM/JPEG/PNG).
  630. *  The palette file requires a body which is loaded and then discarded.
  631. *
  632. *  Waits 20 seconds for cjpeg/pnmtopng to start then aborts. This check is
  633. *  not fool proof and the PIPE:xxx can be left hanging.
  634. *
  635. *  Prior to version 4.3 fails to determine a screen mode correctly.
  636. *
  637. *  V7.0 did not handle MPIS_BITMAP correctly.
  638. *
  639. *  V7.3 did not set return code when MPIS_BITMAP supplied.
  640. *
  641. *   SEE ALSO
  642. *  MPImageErrorMessage().
  643. *
  644. *****************************************************************************
  645. *
  646. */
  647. BOOL __asm __saveds
  648. SaveMPImageA(register __a0 const UBYTE *file,
  649.                         register __a1 UBYTE *red, register __a2 UBYTE *green,register __a3 UBYTE *blue,
  650.                         register __d0 UWORD width, register __d1 UWORD height,
  651.                         register __a5 struct TagItem *TagList) {
  652.     struct TagItem *ti;
  653.     ULONG camg = (ULONG)INVALID_ID;
  654.     UBYTE *format = NULL;
  655.     UBYTE *palette = NULL;
  656.     ULONG numcols = 0;
  657.     ULONG numcols1;
  658.     BOOL bit12 = FALSE;
  659.     char *modename;
  660.     ULONG id = (ULONG)INVALID_ID;
  661.     struct NameInfo buff;
  662.     BOOL ret;
  663.     BOOL Linear = FALSE;
  664.     UBYTE *GreyMap = NULL;
  665.     UBYTE *OldPal = NULL;
  666.     UBYTE *NewPal = NULL;
  667.     struct BitMap *RetBitMap = NULL;
  668.  
  669.     if (ti = FindTagItem(MPIS_OLDPALETTE,TagList)) {
  670.         OldPal = (UBYTE *)ti->ti_Data;
  671.     }
  672.     if (ti = FindTagItem(MPIS_NEWPALETTE,TagList)) {
  673.         NewPal = (UBYTE *)ti->ti_Data;
  674.     }
  675.     if (ti = FindTagItem(MPIS_BITMAP,TagList)) {
  676.         RetBitMap = (struct BitMap *)ti->ti_Data;
  677.     }
  678.     if (ti = FindTagItem(MPIS_MODE,TagList)) {
  679.         camg = ti->ti_Data;
  680.     }
  681.     else {
  682.         if (ti = FindTagItem(MPIS_MODENAME,TagList)) {
  683.             modename = (char *)(ti->ti_Data);
  684.             if (modename && *modename) {
  685.                 id = NextDisplayInfo(id);
  686.                 while ((id != INVALID_ID) && (camg == INVALID_ID)) {
  687.                     if (GetDisplayInfoData(NULL,(UBYTE *)&buff,sizeof(struct NameInfo),DTAG_NAME,id)) {
  688.                         if (!Stricmp(buff.Name,modename)) {
  689.                             camg = id;
  690.                         }
  691.                     }
  692.                     id = NextDisplayInfo(id);
  693.                 }
  694.             }
  695.         }
  696.     }
  697.     if (ti = FindTagItem(MPIS_FORMAT,TagList)) {
  698.         format = (UBYTE *)(ti->ti_Data);
  699.     }
  700.     if (!format) {
  701.         format = MPI_BW16;
  702.     }
  703.     if (ti = FindTagItem(MPIS_COLOURS,TagList)) {
  704.         numcols = ti->ti_Data;
  705.     }
  706.     if (ti = FindTagItem(MPIS_12BIT,TagList)) {
  707.         bit12 = ti->ti_Data;
  708.     }
  709.     if (ti = FindTagItem(MPIS_LINEAR,TagList)) {
  710.         Linear = ti->ti_Data;
  711.     }
  712.     if (ti = FindTagItem(MPIS_GREYMAP,TagList)) {
  713.         GreyMap = (UBYTE *)(ti->ti_Data);
  714.     }
  715.     if (ti = FindTagItem(MPIS_PALETTE,TagList)) {
  716.         palette = (UBYTE *)(ti->ti_Data);
  717.     }
  718.     if (palette) {
  719.         if (!(numcols1 = LoadPalette(palette))) {
  720.             return FALSE;
  721.         }
  722.         if (numcols > numcols1) {
  723.             numcols = numcols1;
  724.         }
  725.     }
  726.     if (numcols > 256) {
  727.         numcols = 256;
  728.     }
  729.     if (!numcols) {
  730.         numcols = 16;
  731.     }
  732.     if (numcols < 2) {
  733.         numcols = 2;
  734.     }
  735.     if (!SetupScreen()) {
  736.         OpenProgressWindow();
  737.     }
  738.     if (!Stricmp(format,MPI_BW16)) {
  739.         if (GreyMap) {
  740.             int i;
  741.             for (i = 0; i < 16; ++i) {
  742.                 MyPalette[GreyMap[i]][0]=i + (i<<4);
  743.                 MyPalette[GreyMap[i]][1]=i + (i<<4);
  744.                 MyPalette[GreyMap[i]][2]=i + (i<<4);
  745.             }
  746.             ret =    SaveBW16(file,width,height, red, green, blue, MyPalette, camg, GreyMap, Linear, RetBitMap);
  747.         }
  748.         else {
  749.             ret = SaveBW16(file,width,height, red, green, blue, BW16_Palette, camg, DefGreyMap, Linear, RetBitMap);
  750.         }
  751.     }
  752.     else if (!Stricmp(format,MPI_BW256)) {
  753.         if (GreyMap) {
  754.             int i;
  755.             for (i = 0; i < 256; ++i) {
  756.                 MyPalette[GreyMap[i]][0]=i;
  757.                 MyPalette[GreyMap[i]][1]=i;
  758.                 MyPalette[GreyMap[i]][2]=i;
  759.             }
  760.             ret =    SaveBW256(file,width,height, red, green, blue, MyPalette, camg, GreyMap, Linear, RetBitMap);
  761.         }
  762.         else {
  763.             ret =    SaveBW256(file,width,height, red, green, blue, BW256_Palette, camg, DefGreyMap, Linear, RetBitMap);
  764.         }
  765.     }
  766.     else if (!Stricmp(format,MPI_HAM6)) {
  767.         ret =    SaveHAM6(file,width,height, red, green, blue, HAM6_Palette, camg, RetBitMap);
  768.         if (NewPal) {
  769.             CopyNewPal(HAM6_Palette,NewPal,16);
  770.         }
  771.     }
  772.     else if (!Stricmp(format,MPI_HAM8)) {
  773.         ret =    SaveHAM8(file,width,height, red, green, blue, HAM8_Palette, camg, RetBitMap);
  774.         if (NewPal) {
  775.             CopyNewPal(HAM8_Palette,NewPal,64);
  776.         }
  777.     }
  778.     else if (!Stricmp(format,MPI_ILBM24)) {
  779.         ret =    Save24(file,width,height, red, green, blue, camg);
  780.     }
  781.     else if (!Stricmp(format,MPI_PPM)) {
  782.         ret =    SavePPM(file,width,height, red, green, blue, 0);
  783.     }
  784.     else if (!Stricmp(format,MPI_HAM6P)) {
  785.         if (OldPal || palette || ComputePal12(16,width,height,red,green,blue)) {
  786.             if (OldPal) {
  787.                 CopyOldPal(OldPal,MyPalette,16);
  788.             }
  789.             ret =    SaveHAM6(file,width,height, red, green, blue, MyPalette, camg, RetBitMap);
  790.             if (NewPal) {
  791.                 CopyNewPal(MyPalette,NewPal,16);
  792.             }
  793.         }
  794.         else {
  795.             ret = FALSE;
  796.         }
  797.     }
  798.     else if (!Stricmp(format,MPI_HAM8P)) {
  799.         if (OldPal || palette || ComputePalette(64,width,height,red,green,blue)) {
  800.             if (OldPal) {
  801.                 CopyOldPal(OldPal,MyPalette,64);
  802.             }
  803.             ret =    SaveHAM8(file,width,height, red, green, blue, MyPalette, camg, RetBitMap);
  804.             if (NewPal) {
  805.                 CopyNewPal(MyPalette,NewPal,64);
  806.             }
  807.         }
  808.         else {
  809.             ret = FALSE;
  810.         }
  811.     }
  812.     else if (!Stricmp(format,MPI_COLOUR) && !bit12) {
  813.         if (OldPal || palette || ComputePalette(numcols,width,height,red,green,blue)) {
  814.             if (OldPal) {
  815.                 CopyOldPal(OldPal,MyPalette,numcols);
  816.             }
  817.             ret =    SaveColour(file,width,height, red, green, blue, camg, numcols,RetBitMap);
  818.             if (NewPal) {
  819.                 CopyNewPal(MyPalette,NewPal,numcols);
  820.             }
  821.         }
  822.         else {
  823.             ret = FALSE;
  824.         }
  825.     }
  826.     else if (!Stricmp(format,MPI_COLOUR) && bit12) {
  827.         if (OldPal || palette || ComputePal12(numcols,width,height,red,green,blue)) {
  828.             if (OldPal) {
  829.                 CopyOldPal(OldPal,MyPalette,numcols);
  830.             }
  831.             ret =    SaveColour12(file,width,height, red, green, blue, camg, numcols, RetBitMap);
  832.             if (NewPal) {
  833.                 CopyNewPal(MyPalette,NewPal,numcols);
  834.             }
  835.         }
  836.         else {
  837.             ret = FALSE;
  838.         }
  839.     }
  840.     else if (!Stricmp(format,MPI_EHB)) {
  841.         if (OldPal) {
  842.             CopyOldPal(OldPal,MyPalette,32);
  843.         }
  844.         if (OldPal || palette || ComputePalEHB(width,height,red,green,blue)) {
  845.             ret =    SaveEHB(file,width,height, red, green, blue, camg, RetBitMap);
  846.             if (NewPal) {
  847.                 CopyNewPal(MyPalette,NewPal,64);
  848.             }
  849.         }
  850.         else {
  851.             ret = FALSE;
  852.         }
  853.     }
  854.     else if (!Stricmp(format,MPI_JPEG)) {
  855.         ret =    SavePPM(file,width,height, red, green, blue, 1);
  856.     }
  857.     else if (!Stricmp(format,MPI_PNG)) {
  858.         ret =    SavePPM(file,width,height, red, green, blue, 2);
  859.     }
  860.     else if (!Stricmp(format,MPI_DCTV3)) {
  861.         ret =    SaveDCTV(file,width,height, red, green, blue, camg, FALSE, RetBitMap);
  862.     }
  863.     else if (!Stricmp(format,MPI_DCTV4)) {
  864.         ret =    SaveDCTV(file,width,height, red, green, blue, camg, TRUE, RetBitMap);
  865.     }
  866.     else {
  867.         sprintf(ErrorMessage,GetMg(MSG_ERR_INVF),format);
  868.         ret =  FALSE;
  869.     }
  870.     CloseProgressWindow();
  871.     CloseDownScreen();
  872.     return ret;
  873. }
  874.  
  875. // returns 0 for error - message already set up
  876. // otherwise returns number of colours in palette
  877. static ULONG
  878. LoadPalette(UBYTE *filename) {
  879.     struct ILBMInfo ilbm = {0};        // ILBM stuff
  880.     int i;
  881.     ULONG numcols;
  882.  
  883.     AddMessageNo(MSG_LOADP);
  884.     if (ilbm.ParseInfo.iff = AllocIFF()) {
  885.         ilbm.ParseInfo.propchks = props;
  886.         ilbm.ParseInfo.collectchks = nowt;
  887.         ilbm.ParseInfo.stopchks = stops;
  888.         if (loadbrush(&ilbm,(char *)filename)) {
  889.             closeifile(&(ilbm.ParseInfo));
  890.             unloadbrush(&ilbm);
  891.             FreeIFF(ilbm.ParseInfo.iff);
  892.             return 0;
  893.         }
  894.         closeifile(&(ilbm.ParseInfo));
  895.         numcols = ilbm.ncolors;
  896.         AddMessageNo(MSG_GETC);
  897.         for (i=0; i < numcols; ++i) {
  898.             MyPalette[i][0]=(ilbm.colortable32[i].r)>>24;
  899.             MyPalette[i][1]=(ilbm.colortable32[i].g)>>24;
  900.             MyPalette[i][2]=(ilbm.colortable32[i].b)>>24;
  901.         }
  902.         unloadbrush(&ilbm);
  903.         FreeIFF(ilbm.ParseInfo.iff);
  904.         return numcols;
  905.     }
  906.     else {
  907.         strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
  908.         return 0;
  909.     }
  910. }
  911.  
  912. #define HSIZE     32768          /* size of image histogram    */
  913. /* Macros for converting between (r,g,b)-colors and 15-bit     */
  914. /* colors follow.                                              */
  915. #define RGB(r,g,b) (UWORD)(((b)&~7)<<7)|(((g)&~7)<<2)|((r)>>3)
  916. static BOOL
  917. ComputePalette(UWORD Depth,UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue) {
  918.     UWORD *hist;
  919.     UBYTE *r=red,*g=green,*b=blue;
  920.     int i,j;
  921.     if (hist = AllocVec(sizeof(UWORD)*HSIZE*2,MEMF_CLEAR)) {
  922.         AddMessageNo(MSG_HIST);
  923.         SetMax(height);
  924.         memset(MyPalette,0,256*3);
  925.         for (i = 0; i < height; ++i) {
  926.             SetCur(i);
  927.             for (j = 0; j < width; ++j) {
  928.                 hist[RGB(*r++,*g++,*b++)] += 1;
  929.             }
  930.         }
  931.         AddMessageNo(MSG_CPAL);
  932.         MedianCut(hist,MyPalette,Depth,&(hist[HSIZE]));
  933.         FreeVec(hist);
  934.         return TRUE;
  935.     }
  936.     else {
  937.         strcpy(ErrorMessage,GetMg(MSG_ERR_NOMEM));
  938.         return FALSE;
  939.     }
  940. }
  941.  
  942. #define HSIZE6    4096           /* size of image histogram    */
  943. /* Macros for converting between (r,g,b)-colors and 12-bit     */
  944. /* colors follow.                                              */
  945. #define RGB6(r,g,b) (UWORD)((((b)&~15)<<4)|((g)&~15)|((r)>>4))
  946. #define RED6(x)     ((((x)&15)<<4)|((x)&15))
  947. #define GREEN6(x)   (((((x)>>4)&15)<<4)|((((x)>>4)&15)))
  948. #define BLUE6(x)    (((((x)>>8)&15)<<4)|((((x)>>8)&15)))
  949. static BOOL
  950. ComputePal12(UWORD Depth, UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue) {
  951.     UWORD *hist;
  952.     UBYTE *r=red,*g=green,*b=blue;
  953.     int i,j;
  954.     if (hist = AllocVec(sizeof(UWORD)*HSIZE6*2,MEMF_CLEAR)) {
  955.         AddMessageNo(MSG_HIST);
  956.         SetMax(height);
  957.         memset(MyPalette,0,256*3);
  958.         for (i = 0; i < height; ++i) {
  959.             SetCur(i);
  960.             for (j = 0; j < width; ++j) {
  961.                 hist[RGB6(*r++,*g++,*b++)] += 1;
  962.             }
  963.         }
  964.         AddMessageNo(MSG_CPAL);
  965.         MedHam6(hist,MyPalette,Depth,&(hist[HSIZE6]));
  966.         FreeVec(hist);
  967.         return TRUE;
  968.     }
  969.     else {
  970.         strcpy(ErrorMessage,GetMg(MSG_ERR_NOMEM));
  971.         return FALSE;
  972.     }
  973. }
  974.  
  975. static BOOL
  976. ComputePalEHB(UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue) {
  977.     UWORD *hist;
  978.     UBYTE *r=red,*g=green,*b=blue;
  979.     int i,j,k=0;
  980.     long maxdiff,diff,t;
  981.  
  982.     if (hist = AllocVec(sizeof(UWORD)*HSIZE6*4,MEMF_CLEAR)) {
  983.         AddMessageNo(MSG_HIST);
  984.         memset(MyPalette,0,256*3);
  985.         for (i = 0; i < height; ++i) {
  986.             for (j = 0; j < width; ++j) {
  987.                 if ((*r > 127) || (*g > 127) || (*b > 127)) {
  988.                     hist[RGB6(*r++,*g++,*b++)] += 1;
  989.                 }
  990.                 else {
  991.                     hist[RGB6(*r++,*g++,*b++)+(HSIZE6*2)] += 1;
  992.                 }
  993.             }
  994.         }
  995.         // Compute top 32 colours and bottom 32 colours
  996.         AddMessageNo(MSG_CHPAL);
  997.         MedHam6(hist,MyPalette,32,&(hist[HSIZE6]));
  998.         AddMessageNo(MSG_CLPAL);
  999.         MedHam6(&(hist[HSIZE6*2]),(UBYTE (*)[3])&(MyPalette[32][0]),32,&(hist[HSIZE6*3]));
  1000.         AddMessageNo(MSG_MPAL);
  1001.         for (i = 0; i < 32; i++) {
  1002.             maxdiff = 0x7fffffff;
  1003.             for (j = 32; (j < 64) && maxdiff; ++j) {
  1004.                 t = (int)MyPalette[i][0] - ((int)MyPalette[j][0]*2);
  1005.                 diff = t*t * 2;
  1006.                 if (diff < maxdiff) {
  1007.                     t = (int)MyPalette[i][1] - ((int)MyPalette[j][1]*2);
  1008.                     diff += t*t * 4;
  1009.                     if (diff < maxdiff) {
  1010.                         t = (int)MyPalette[i][2] - ((int)MyPalette[j][2]*2);
  1011.                         diff += t*t;
  1012.                         if (diff < maxdiff) {
  1013.                             maxdiff = diff;
  1014.                             k = j;
  1015.                         }
  1016.                     }
  1017.                 }
  1018.             }
  1019.             for (j = 0; j < 3; ++j) {
  1020.                 t = (MyPalette[i][j] + (MyPalette[k][j]*2)) / 2;
  1021.                 if (t > 255) {
  1022.                     MyPalette[i][k] = 255;
  1023.                 }
  1024.                 else {
  1025.                     MyPalette[i][k] = t;
  1026.                 }
  1027.             }
  1028.         }
  1029.         FreeVec(hist);
  1030.         return TRUE;
  1031.     }
  1032.     else {
  1033.         strcpy(ErrorMessage,GetMg(MSG_ERR_NOMEM));
  1034.         return FALSE;
  1035.     }
  1036. }
  1037.  
  1038. // Hack a sort of modeid (caller must merge in HAM itself...)
  1039. static ULONG
  1040. GetMode(UWORD height, UWORD width,UWORD depth, ULONG camg, ULONG flags, const UBYTE *filename) {
  1041.     ULONG mode=0;
  1042.     if (camg != INVALID_ID) {
  1043.         return camg;
  1044.     }
  1045.     AddMessageNo(MSG_CAMG);
  1046. //    if (((ULONG)filename < 61) || !filename || !*filename) { 7.4 remove filename hack
  1047.     if (!filename || !*filename) {
  1048.         camg = BestModeID(BIDTAG_DIPFMustHave,        flags,
  1049.                                 BIDTAG_DIPFMustNotHave,    SPECIAL_FLAGS & (~flags),
  1050.                                 BIDTAG_NominalWidth,        width,
  1051.                                 BIDTAG_NominalHeight,    height,
  1052.                                 BIDTAG_Depth,                depth,
  1053.                                 TAG_END);
  1054.         if (camg != INVALID_ID) {
  1055.             return camg;
  1056.         }
  1057.     }
  1058.     if (depth == 24) {    // 24 bit so can set both hires and lace
  1059.         if (width > 400) {    // more than lores overscan
  1060.             mode |= HIRES;
  1061.         }
  1062.         if (height > 300) {    // more than nolace overscan
  1063.             mode |= LACE;
  1064.         }
  1065.     }
  1066.     else {
  1067.         if (depth > 6) {    // Must be AGA only so can have hires
  1068.             if (width > 400) {    // more than lores overscan
  1069.                 mode |= HIRES;
  1070.             }
  1071.             if (height > 300) {    // more than nolace overscan
  1072.                 mode |= LACE;
  1073.             }
  1074.         }
  1075.         else {
  1076.             if (depth > 4) {    // May be HAM6 or 32 colour or EHB - don't set HIRES for non-AGA
  1077.                 if (height > 300) {
  1078.                     mode |= LACE;
  1079.                 }
  1080.             }
  1081.             else {    // 16 or less colours
  1082.                 if (width > 400) {    // more than lores overscan
  1083.                     mode |= HIRES;
  1084.                 }
  1085.                 if (height > 300) {    // more than nolace overscan
  1086.                     mode |= LACE;
  1087.                 }
  1088.             }
  1089.         }
  1090.     }
  1091.     if (flags & DIPF_IS_HAM) {
  1092.         return (mode | HAM);
  1093.     }
  1094.     if (flags & DIPF_IS_EXTRAHALFBRITE) {
  1095.         return (mode | EXTRA_HALFBRITE);
  1096.     }
  1097.     return mode;
  1098. }
  1099.  
  1100. /* save 16 grey scale
  1101.  * FileName : file to save
  1102.  * width    : width of image
  1103.  * height   : height of image
  1104.  * red      : red
  1105.  * green    : green
  1106.  * blue     : blue chunky bit map
  1107.  */
  1108. static BOOL
  1109. SaveBW16(const UBYTE *FileName,USHORT width,USHORT height,
  1110.                   UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg, UBYTE *GreyMap, BOOL Linear,
  1111.                   struct BitMap *NewBitMap) {
  1112.     UBYTE *r,*g,*b;
  1113.     UBYTE *old;
  1114.     UWORD x,y;
  1115.     BOOL OkFlag=FALSE;
  1116.     struct ILBMInfo ilbm = {0};
  1117.     struct MyBitMap *bitmap;
  1118.     struct c2pStruct c2p;
  1119.     int *word,*w;
  1120.     int diff,cur,new,car;
  1121.  
  1122.     AddMessageNo(MSG_SBW16);
  1123.     bitmap = (struct MyBitMap *)NewBitMap;
  1124.     // allocate IFF stuff
  1125.     if ((word = AllocVec((sizeof(int))*(width+1),MEMF_CLEAR)) &&
  1126.          ((NewBitMap) || (bitmap = MyAllocBitMap(width,height,4,FileName)))) {
  1127.         if (ilbm.ParseInfo.iff = AllocIFF()) {
  1128.             if ((red == green) && (red == blue)) {    // grey scale input
  1129.                 r = red;
  1130.                 old = red;
  1131.                 // for each line
  1132.                 AddMessageNo(MSG_INGREY);
  1133.                 SetMax(height);
  1134.                 for (y=0;
  1135.                       y<height;
  1136.                       y++) {
  1137.                     SetCur(y);
  1138.                     w = word;    // Carrys from previous row
  1139.                     diff = 0;    // Carry from last column
  1140.                     car = *w;    // Carry from last row
  1141.                     // for each column
  1142.                     for (x=0;
  1143.                           x < width;
  1144.                           x++) {
  1145.                         // convert rgb to 16 grey scale
  1146.                         cur = *r++ + diff + car;
  1147.                         new = cur / 17;
  1148.                         if (new > 15) {
  1149.                             *old++ = GreyMap[15];
  1150.                             diff = cur - 15;
  1151.                         }
  1152.                         else {
  1153.                             if (new < 0) {
  1154.                                 *old++ = GreyMap[0];
  1155.                                 diff = cur;
  1156.                             }
  1157.                             else {
  1158.                                 *old++ = GreyMap[new];
  1159.                                 diff = cur - (new * 17);
  1160.                             }
  1161.                         }
  1162.                         *w++ = (diff * 3)/8;    //    3/8 to pixel below
  1163.                         car = *w;                // carry to next pixel
  1164.                         *w = diff / 4;            // 2/8 to pixel below right
  1165.                         diff = (diff * 3)/8;    // 3/8 to pixel right;
  1166.                     }
  1167.                 }
  1168.             }
  1169.             else {    // not greyscale input
  1170.                 r = red;
  1171.                 g = green;
  1172.                 b = blue;
  1173.                 old = red;
  1174.                 AddMessageNo(MSG_INCOL);
  1175.                 if (Linear) {
  1176.                     AddMessageNo(MSG_LINEAR);
  1177.                 }
  1178.                 SetMax(height);
  1179.                 // for each line
  1180.                 for (y=0;
  1181.                       y<height;
  1182.                       y++) {
  1183.                     SetCur(y);
  1184.                     w = word;    // Carrys from previous row
  1185.                     diff = 0;    // Carry from last column
  1186.                     car = *w;    // Carry from last row
  1187.                     // for each column
  1188.                     if (Linear) {
  1189.                         for (x=0;
  1190.                               x < width;
  1191.                               x++) {
  1192.                             // convert rgb to 16 grey scale
  1193.                             cur = ((int)*r++ + (int)*g++ + (int)*b++)/3 + diff + car;
  1194.                             new = cur / 17;
  1195.                             if (new > 15) {
  1196.                                 *old++ = GreyMap[15];
  1197.                                 diff = cur - 15;
  1198.                             }
  1199.                             else {
  1200.                                 if (new < 0) {
  1201.                                     *old++ = GreyMap[0];
  1202.                                     diff = cur;
  1203.                                 }
  1204.                                 else {
  1205.                                     *old++ = GreyMap[new];
  1206.                                     diff = cur - (new * 17);
  1207.                                 }
  1208.                             }
  1209.                             *w++ = (diff * 3)/8;    //    3/8 to pixel below
  1210.                             car = *w;                // carry to next pixel
  1211.                             *w = diff / 4;            // 2/8 to pixel below right
  1212.                             diff = (diff * 3)/8;    // 3/8 to pixel right;
  1213.                         }
  1214.                     }
  1215.                     else {
  1216.                         for (x=0;
  1217.                               x < width;
  1218.                               x++) {
  1219.                             // convert rgb to 16 grey scale
  1220.                             cur = (30 * (int)*r++) + (59 * (int)*g++) + (11 * (int)*b++) + diff + car + 100;
  1221.                             new = cur / 1700;
  1222.                             if (new > 15) {
  1223.                                 *old++ = GreyMap[15];
  1224.                                 diff = cur - (15 * 1700);
  1225.                             }
  1226.                             else {
  1227.                                 if (new < 0) {
  1228.                                     *old++ = GreyMap[0];
  1229.                                     diff = cur;
  1230.                                 }
  1231.                                 else {
  1232.                                     *old++ = GreyMap[new];
  1233.                                     diff = cur - (new * 1700);
  1234.                                 }
  1235.                             }
  1236.                             *w++ = (diff * 3)/8;    //    3/8 to pixel below
  1237.                             car = *w;                // carry to next pixel
  1238.                             *w = diff / 4;            // 2/8 to pixel below right
  1239.                             diff = (diff * 3)/8;    // 3/8 to pixel right;
  1240.                         }
  1241.                     }
  1242.                 }
  1243.             }
  1244.             // convert chunky to planar
  1245.             c2p.bmap = (struct BitMap *)bitmap;
  1246.             c2p.startX = 0;
  1247.             c2p.startY = 0;
  1248.             c2p.width = width;
  1249.             c2p.height = height;
  1250.             c2p.chunkybuffer = red;
  1251.             ChunkyToPlanar(&c2p);
  1252.             // and save IFF
  1253.             AddMessageNo(MSG_SILBM);
  1254.             if (!NewBitMap) {
  1255.                 OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,4,camg,0,FileName),
  1256.                                      width,  height, width, height,
  1257.                                      palette, 16, 8,    /* colortable */
  1258.                                      mskNone, 0,    /* masking, transparent */
  1259.                                      NULL, NULL,     /* chunklisMP */
  1260.                                      (UBYTE *)FileName,4);
  1261.             }
  1262.             else {
  1263.                 OkFlag = TRUE;
  1264.             }
  1265.             // Close everything down cleanly
  1266.             FreeIFF(ilbm.ParseInfo.iff);
  1267.         }
  1268.         else {
  1269.             OkFlag = FALSE;
  1270.             strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
  1271.         }
  1272.         if (!NewBitMap) {
  1273.             MyFreeBitMap(bitmap,FileName);
  1274.         }
  1275.     }
  1276.     else {
  1277.         strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
  1278.         OkFlag = FALSE;
  1279.     }
  1280.     if (word) {
  1281.         FreeVec(word);
  1282.     }
  1283.     return OkFlag;
  1284. }
  1285.  
  1286. /* save 256 grey scale
  1287.  * see SaveBW16()
  1288.  */
  1289. static BOOL
  1290. SaveBW256(const UBYTE *FileName,USHORT width,USHORT height,
  1291.                   UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg, UBYTE *GreyMap, BOOL Linear,
  1292.                   struct BitMap *NewBitMap) {
  1293.     UBYTE *r,*g,*b;
  1294.     UBYTE *old;
  1295.     UWORD x,y;
  1296.     BOOL OkFlag=FALSE;
  1297.     struct ILBMInfo ilbm = {0};
  1298.     struct MyBitMap *bitmap;
  1299.     struct c2pStruct c2p;
  1300.     int *word,*w;
  1301.     int diff,cur,new,car;
  1302.  
  1303.     AddMessageNo(MSG_SBW256);
  1304.     bitmap = (struct MyBitMap *)NewBitMap;
  1305.     // allocate IFF stuff
  1306.     if ((word = AllocVec((sizeof(int))*(width+1),MEMF_CLEAR)) &&
  1307.          ((NewBitMap) || (bitmap = MyAllocBitMap(width,height,8,FileName)))) {
  1308.         if (ilbm.ParseInfo.iff = AllocIFF()) {
  1309.             if ((red == green) && (red == blue)) {    // grey scale input
  1310.                 r = red;
  1311.                 old = red;
  1312.                 AddMessageNo(MSG_INGREY);
  1313.                 SetMax(height);
  1314.                 for (y=0;
  1315.                       y<height;
  1316.                       y++) {
  1317.                     SetCur(y);
  1318.                     w = word;    // Carrys from previous row
  1319.                     diff = 0;    // Carry from last column
  1320.                     car = *w;    // Carry from last row
  1321.                     for (x=0;
  1322.                           x < width;
  1323.                           x++) {
  1324.                         // convert rgb to 256 grey scale
  1325.                         cur = (*r++ * 256) + diff + car;
  1326.                         new = cur / 256;
  1327.                         if (new > 255) {
  1328.                             *old++ = GreyMap[255];
  1329.                             diff = cur - (255 * 256);
  1330.                         }
  1331.                         else {
  1332.                             if (new < 0) {
  1333.                                 *old++ = GreyMap[0];
  1334.                                 diff = cur;
  1335.                             }
  1336.                             else {
  1337.                                 *old++ = GreyMap[new];
  1338.                                 diff = cur - (new * 256);
  1339.                             }
  1340.                         }
  1341.                         *w++ = (diff * 3)/8;    //    3/8 to pixel below
  1342.                         car = *w;                // carry to next pixel
  1343.                         *w = diff / 4;            // 2/8 to pixel below right
  1344.                         diff = (diff * 3)/8;    // 3/8 to pixel right;
  1345.                     }
  1346.                 }
  1347.             }
  1348.             else {
  1349.                 r = red;
  1350.                 g = green;
  1351.                 b = blue;
  1352.                 old = red;
  1353.                 AddMessageNo(MSG_INCOL);
  1354.                 if (Linear) {
  1355.                     AddMessageNo(MSG_LINEAR);
  1356.                 }
  1357.                 SetMax(height);
  1358.                 for (y=0;
  1359.                       y<height;
  1360.                       y++) {
  1361.                     SetCur(y);
  1362.                     w = word;    // Carrys from previous row
  1363.                     diff = 0;    // Carry from last column
  1364.                     car = *w;    // Carry from last row
  1365.                     if (Linear) {
  1366.                         for (x=0;
  1367.                               x < width;
  1368.                               x++) {
  1369.                             // convert rgb to 256 grey scale
  1370.                             cur = (int)*r++ + (int)*g++ + (int)*b++ + diff + car;
  1371.                             new = cur / 3;
  1372.                             if (new > 255) {
  1373.                                 *old++ = GreyMap[255];
  1374.                                 diff = cur - (255 * 3);
  1375.                             }
  1376.                             else {
  1377.                                 if (new < 0) {
  1378.                                     *old++ = GreyMap[0];
  1379.                                     diff = cur;
  1380.                                 }
  1381.                                 else {
  1382.                                     *old++ = GreyMap[new];
  1383.                                     diff = cur - (new * 3);
  1384.                                 }
  1385.                             }
  1386.                             *w++ = (diff * 3)/8;    //    3/8 to pixel below
  1387.                             car = *w;                // carry to next pixel
  1388.                             *w = diff / 4;            // 2/8 to pixel below right
  1389.                             diff = (diff * 3)/8;    // 3/8 to pixel right;
  1390.                         }
  1391.                     }
  1392.                     else {
  1393.                         for (x=0;
  1394.                               x < width;
  1395.                               x++) {
  1396.                             // convert rgb to 256 grey scale
  1397.                             cur = (30 * (int)*r++) + (59 * (int)*g++) + (11 * (int)*b++) + diff + car;
  1398.                             new = cur / 100;
  1399.                             if (new > 255) {
  1400.                                 *old++ = GreyMap[255];
  1401.                                 diff = cur - (255 * 100);
  1402.                             }
  1403.                             else {
  1404.                                 if (new < 0) {
  1405.                                     *old++ = GreyMap[0];
  1406.                                     diff = cur;
  1407.                                 }
  1408.                                 else {
  1409.                                     *old++ = GreyMap[new];
  1410.                                     diff = cur - (new * 100);
  1411.                                 }
  1412.                             }
  1413.                             *w++ = (diff * 3)/8;    //    3/8 to pixel below
  1414.                             car = *w;                // carry to next pixel
  1415.                             *w = diff / 4;            // 2/8 to pixel below right
  1416.                             diff = (diff * 3)/8;    // 3/8 to pixel right;
  1417.                         }
  1418.                     }
  1419.                 }
  1420.             }
  1421.             c2p.bmap = (struct BitMap *)bitmap;
  1422.             c2p.startX = 0;
  1423.             c2p.startY = 0;
  1424.             c2p.width = width;
  1425.             c2p.height = height;
  1426.             c2p.chunkybuffer = red;
  1427.             ChunkyToPlanar(&c2p);
  1428.             AddMessageNo(MSG_SILBM);
  1429.             if (!NewBitMap) {
  1430.                 OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,8,camg,0,FileName),
  1431.                                      width,  height, width, height,
  1432.                                      palette, 256, 8,    /* colortable */
  1433.                                      mskNone, 0,    /* masking, transparent */
  1434.                                      NULL, NULL,     /* chunklists */
  1435.                                      (UBYTE *)FileName,8);
  1436.             }
  1437.             else {
  1438.                 OkFlag = TRUE;
  1439.             }
  1440.             // Close everything down cleanly
  1441.             FreeIFF(ilbm.ParseInfo.iff);
  1442.         }
  1443.         else {
  1444.             OkFlag = FALSE;
  1445.             strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
  1446.         }
  1447.         if (!NewBitMap) {
  1448.             MyFreeBitMap(bitmap,FileName);
  1449.         }
  1450.     }
  1451.     else {
  1452.         strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
  1453.         OkFlag = FALSE;
  1454.     }
  1455.     if (word) {
  1456.         FreeVec(word);
  1457.     }
  1458.     return OkFlag;
  1459. }
  1460.  
  1461. /* save HAM6
  1462.  * see SaveBW16()
  1463.  */
  1464. static BOOL
  1465. SaveHAM6(const UBYTE *FileName,USHORT width,USHORT height,
  1466.                   UBYTE *red, UBYTE *green, UBYTE *blue,UBYTE palette[][3], ULONG camg, struct BitMap *NewBitMap) {
  1467.     UBYTE *r,*g,*b,*p;
  1468.     UBYTE rr,gg,bb;
  1469.     UBYTE *old;
  1470.     UWORD x,y;
  1471.     ULONG maxdiff;
  1472.     ULONG diff;
  1473.     LONG t;
  1474.     UWORD k;
  1475.     UWORD index=0;
  1476.     BOOL OkFlag=FALSE;
  1477.     UBYTE lr,lg,lb;
  1478.     struct ILBMInfo ilbm = {0};
  1479.     struct MyBitMap *bitmap;
  1480.     struct c2pStruct c2p;
  1481.     int *word = NULL,*wr,*wg,*wb;
  1482.     int diffr,curr,newr,carr;
  1483.     int diffg,curg,newg,carg;
  1484.     int diffb,curb,newb,carb;
  1485.     UBYTE *InvMap;
  1486.     ULONG *Diffs = NULL;
  1487.     int i,ir,ig,ib;
  1488.  
  1489.     AddMessageNo(MSG_SHAM6);
  1490.     bitmap = (struct MyBitMap *)NewBitMap;
  1491.     if ((InvMap = AllocVec(4906,MEMF_ANY)) &&
  1492.          (Diffs = AllocVec(4906*sizeof(ULONG),MEMF_ANY)) &&
  1493.          (word = AllocVec((sizeof(int))*(width+1)*3,MEMF_CLEAR)) &&
  1494.          ((NewBitMap) || (bitmap = MyAllocBitMap(width,height,6,FileName)))) {
  1495.         if (ilbm.ParseInfo.iff = AllocIFF()) {
  1496.             AddMessageNo(MSG_BM);
  1497.             // Compute inverse color map
  1498.             for (i = 0; i < 4096; ++i) {
  1499.                 ir = RED6(i);
  1500.                 ig = GREEN6(i);
  1501.                 ib = BLUE6(i);
  1502.                 // Find closest color
  1503.                 maxdiff = 0x7FFFFFFF;
  1504.                 p = &(palette[0][0]);
  1505.                 for (k = 0;
  1506.                       (k < 16) && maxdiff;
  1507.                       ++k) {
  1508.                     t = ir - (int)*p++;
  1509.                     diff = t*t * 2;
  1510.                     if (diff < maxdiff) {
  1511.                         t = ig - (int)*p++;
  1512.                         diff += t*t * 4;
  1513.                         if (diff < maxdiff) {
  1514.                             t = ib - (int)*p++;
  1515.                             diff += t*t;
  1516.                             if (diff < maxdiff) {
  1517.                                 maxdiff = diff;
  1518.                                 index = k;
  1519.                             }
  1520.                         }
  1521.                         else {
  1522.                             ++p;
  1523.                         }
  1524.                     }
  1525.                     else {
  1526.                         ++p;
  1527.                         ++p;
  1528.                     }
  1529.                 }
  1530.                 InvMap[i] = index;
  1531.                 Diffs[i] = maxdiff;
  1532.             }
  1533.             r = red;
  1534.             g = green;
  1535.             b = blue;
  1536.             old = red;
  1537.             AddMessageNo(MSG_REMAP);
  1538.             SetMax(height);
  1539.             for (y=0;
  1540.                   y<height;
  1541.                   y++) {
  1542.                 SetCur(y);
  1543.                 lr = palette[0][0];
  1544.                 lg = palette[0][1];
  1545.                 lb = palette[0][2];
  1546.                 wr = word;    // Carrys from previous row
  1547.                 diffr = 0;    // Carry from last column
  1548.                 carr = *wr;    // Carry from last row
  1549.                 wg = word+(width+1);
  1550.                 diffg = 0;
  1551.                 carg = *wg;
  1552.                 wb = word+(2*(width+1));
  1553.                 diffb = 0;
  1554.                 carb = *wb;
  1555.                 for (x=0;
  1556.                       x < width;
  1557.                       x++) {
  1558.                     curr = ((int)*r * 256) + diffr + carr;
  1559.                     newr = curr / 256;
  1560.                     if (newr > 255) {
  1561.                         rr = 255;
  1562.                     }
  1563.                     else {
  1564.                         if (newr < 0) {
  1565.                             rr = 0;
  1566.                         }
  1567.                         else {
  1568.                             rr = newr;
  1569.                         }
  1570.                     }
  1571.                     curg = ((int)*g * 256) + diffg + carg;
  1572.                     newg = curg / 256;
  1573.                     if (newg > 255) {
  1574.                         gg = 255;
  1575.                     }
  1576.                     else {
  1577.                         if (newg < 0) {
  1578.                             gg = 0;
  1579.                         }
  1580.                         else {
  1581.                             gg = newg;
  1582.                         }
  1583.                     }
  1584.                     curb = ((int)*b * 256) + diffb + carb;
  1585.                     newb = curb / 256;
  1586.                     if (newb > 255) {
  1587.                         bb = 255;
  1588.                     }
  1589.                     else {
  1590.                         if (newb < 0) {
  1591.                             bb = 0;
  1592.                         }
  1593.                         else {
  1594.                             bb = newb;
  1595.                         }
  1596.                     }
  1597.                     // colour if we use HAM to change R or G or B
  1598.                     palette[16][0] = rr;
  1599.                     palette[16][1] = lg;
  1600.                     palette[16][2] = lb;
  1601.                     palette[17][0] = lr;
  1602.                     palette[17][1] = gg;
  1603.                     palette[17][2] = lb;
  1604.                     palette[18][0] = lr;
  1605.                     palette[18][1] = lg;
  1606.                     palette[18][2] = bb;
  1607.                     // Find closest color
  1608.                     index = InvMap[RGB6(rr,gg,bb)];
  1609.                     maxdiff = Diffs[RGB6(rr,gg,bb)];
  1610.                     p = &(palette[18][2]);
  1611.                     for (k = 0;
  1612.                           (k < 3) && maxdiff;
  1613.                           ++k) {
  1614.                         t = (int)bb - (int)*p--;
  1615.                         diff = t*t;
  1616.                         if (diff < maxdiff) {
  1617.                             t = (int)gg - (int)*p--;
  1618.                             diff += t*t * 4;
  1619.                             if (diff < maxdiff) {
  1620.                                 t = (int)rr - (int)*p--;
  1621.                                 diff += t*t * 2;
  1622.                                 if (diff < maxdiff) {
  1623.                                     maxdiff = diff;
  1624.                                     index = 18 - k;
  1625.                                 }
  1626.                             }
  1627.                             else {
  1628.                                 --p;
  1629.                             }
  1630.                         }
  1631.                         else {
  1632.                             --p;
  1633.                             --p;
  1634.                         }
  1635.                     }
  1636.                     lr = palette[index][0];
  1637.                     lg = palette[index][1];
  1638.                     lb = palette[index][2];
  1639.                     // FS dither
  1640.                     diffr = curr - (lr * 256);
  1641.                     *wr++ = (diffr * 3)/8;    //    3/8 to pixel below
  1642.                     carr = *wr;                    // carry to next pixel
  1643.                     *wr = diffr / 4;            // 2/8 to pixel below right
  1644.                     diffr = (diffr * 3)/8;    // 3/8 to pixel right;
  1645.                     diffg = curg - (lg * 256);
  1646.                     *wg++ = (diffg * 3)/8;
  1647.                     carg = *wg;
  1648.                     *wg = diffg / 4;
  1649.                     diffg = (diffg * 3)/8;
  1650.                     diffb = curb - (lb * 256);
  1651.                     *wb++ = (diffb * 3)/8;
  1652.                     carb = *wb;
  1653.                     *wb = diffb / 4;
  1654.                     diffb = (diffb * 3)/8;
  1655.                     // Set HAM bits if required
  1656.                     if (index == 16) {
  1657.                         *old++ = (rr>>4) | 0x20;
  1658.                     }
  1659.                     else {
  1660.                         if (index == 17) {
  1661.                             *old++ = (gg>>4) | 0x30;
  1662.                         }
  1663.                         else {
  1664.                             if (index == 18) {
  1665.                                 *old++ = (bb>>4) | 0x10;
  1666.                             }
  1667.                             else {
  1668.                                 *old++ = index;
  1669.                             }
  1670.                         }
  1671.                     }
  1672.                     r++;
  1673.                     g++;
  1674.                     b++;
  1675.                 }
  1676.             }
  1677.             c2p.bmap = (struct BitMap *)bitmap;
  1678.             c2p.startX = 0;
  1679.             c2p.startY = 0;
  1680.             c2p.width = width;
  1681.             c2p.height = height;
  1682.             c2p.chunkybuffer = red;
  1683.             ChunkyToPlanar(&c2p);
  1684.             AddMessageNo(MSG_SILBM);
  1685.             if (!NewBitMap) {
  1686.                 OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,6,camg,DIPF_IS_HAM,FileName),
  1687.                                      width,  height, width, height,
  1688.                                      palette, 16, 8,    /* colortable */
  1689.                                      mskNone, 0,    /* masking, transparent */
  1690.                                      NULL, NULL,     /* chunklists */
  1691.                                      (UBYTE *)FileName,6);
  1692.             }
  1693.             else {
  1694.                 OkFlag = TRUE;
  1695.             }
  1696.             // Close everything down cleanly
  1697.             FreeIFF(ilbm.ParseInfo.iff);
  1698.         }
  1699.         else {
  1700.             strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
  1701.             OkFlag = FALSE;
  1702.         }
  1703.         if (!NewBitMap) {
  1704.             MyFreeBitMap(bitmap,FileName);
  1705.         }
  1706.     }
  1707.     else {
  1708.         strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
  1709.         OkFlag = FALSE;
  1710.     }
  1711.     if (word) {
  1712.         FreeVec(word);
  1713.     }
  1714.     if (InvMap) {
  1715.         FreeVec(InvMap);
  1716.     }
  1717.     if (Diffs) {
  1718.         FreeVec(Diffs);
  1719.     }
  1720.     return OkFlag;
  1721. }
  1722.  
  1723. /* save HAM8
  1724.  * see SaveHAM6()
  1725.  */
  1726. static BOOL
  1727. SaveHAM8(const UBYTE *FileName,USHORT width,USHORT height,
  1728.                   UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg, struct BitMap *NewBitMap) {
  1729.     UBYTE *r,*g,*b,*p;
  1730.     UBYTE rr,gg,bb;
  1731.     UBYTE *old;
  1732.     UWORD x,y;
  1733.     ULONG maxdiff;
  1734.     ULONG diff;
  1735.     LONG t;
  1736.     UWORD k;
  1737.     UWORD index=0;
  1738.     BOOL OkFlag=FALSE;
  1739.     UBYTE lr,lg,lb;
  1740.     struct ILBMInfo ilbm = {0};
  1741.     struct MyBitMap *bitmap;
  1742.     struct c2pStruct c2p;
  1743.     int *word,*wr,*wg,*wb;
  1744.     int diffr,curr,newr,carr;
  1745.     int diffg,curg,newg,carg;
  1746.     int diffb,curb,newb,carb;
  1747.  
  1748.     AddMessageNo(MSG_SHAM8);
  1749.     bitmap = (struct MyBitMap *)NewBitMap;
  1750.     if ((word = AllocVec((sizeof(int))*(width+1)*3,MEMF_CLEAR)) &&
  1751.          ((NewBitMap) || (bitmap = MyAllocBitMap(width,height,8,FileName)))) {
  1752.         if (ilbm.ParseInfo.iff = AllocIFF()) {
  1753.             r = red;
  1754.             g = green;
  1755.             b = blue;
  1756.             old = red;
  1757.             AddMessageNo(MSG_REMAP);
  1758.             SetMax(height);
  1759.             for (y=0;
  1760.                   y<height;
  1761.                   y++) {
  1762.                 SetCur(y);
  1763.                 lr = palette[0][0];
  1764.                 lg = palette[0][1];
  1765.                 lb = palette[0][2];
  1766.                 wr = word;    // Carrys from previous row
  1767.                 diffr = 0;    // Carry from last column
  1768.                 carr = *wr;    // Carry from last row
  1769.                 wg = word+(width+1);
  1770.                 diffg = 0;
  1771.                 carg = *wg;
  1772.                 wb = word+(2*(width+1));
  1773.                 diffb = 0;
  1774.                 carb = *wb;
  1775.                 for (x=0;
  1776.                       x < width;
  1777.                       x++) {
  1778.                     curr = ((int)*r * 256) + diffr + carr;
  1779.                     newr = curr / 256;
  1780.                     if (newr > 255) {
  1781.                         rr = 255;
  1782.                     }
  1783.                     else {
  1784.                         if (newr < 0) {
  1785.                             rr = 0;
  1786.                         }
  1787.                         else {
  1788.                             rr = newr;
  1789.                         }
  1790.                     }
  1791.                     curg = ((int)*g * 256) + diffg + carg;
  1792.                     newg = curg / 256;
  1793.                     if (newg > 255) {
  1794.                         gg = 255;
  1795.                     }
  1796.                     else {
  1797.                         if (newg < 0) {
  1798.                             gg = 0;
  1799.                         }
  1800.                         else {
  1801.                             gg = newg;
  1802.                         }
  1803.                     }
  1804.                     curb = ((int)*b * 256) + diffb + carb;
  1805.                     newb = curb / 256;
  1806.                     if (newb > 255) {
  1807.                         bb = 255;
  1808.                     }
  1809.                     else {
  1810.                         if (newb < 0) {
  1811.                             bb = 0;
  1812.                         }
  1813.                         else {
  1814.                             bb = newb;
  1815.                         }
  1816.                     }
  1817.                     palette[64][0] = rr;
  1818.                     palette[64][1] = lg;
  1819.                     palette[64][2] = lb;
  1820.                     palette[65][0] = lr;
  1821.                     palette[65][1] = gg;
  1822.                     palette[65][2] = lb;
  1823.                     palette[66][0] = lr;
  1824.                     palette[66][1] = lg;
  1825.                     palette[66][2] = bb;
  1826.                     // Find closest color
  1827.                     maxdiff = 0x7FFFFFFF;
  1828.                     p = &(palette[66][2]);
  1829.                     for (k = 0;
  1830.                           (k < 67) && maxdiff;
  1831.                           ++k) {
  1832.                         t = (int)bb - (int)*p--;
  1833.                         diff = t*t;
  1834.                         if (diff < maxdiff) {
  1835.                             t = (int)gg - (int)*p--;
  1836.                             diff += t*t * 4;
  1837.                             if (diff < maxdiff) {
  1838.                                 t = (int)rr - (int)*p--;
  1839.                                 diff += t*t * 2;
  1840.                                 if (diff < maxdiff) {
  1841.                                     maxdiff = diff;
  1842.                                     index = 66 - k;
  1843.                                 }
  1844.                             }
  1845.                             else {
  1846.                                 --p;
  1847.                             }
  1848.                         }
  1849.                         else {
  1850.                             --p;
  1851.                             --p;
  1852.                         }
  1853.                     }
  1854.                     lr = palette[index][0];
  1855.                     lg = palette[index][1];
  1856.                     lb = palette[index][2];
  1857.                     // FS dither
  1858.                     diffr = curr - (lr * 256);
  1859.                     *wr++ = (diffr * 3)/8;    //    3/8 to pixel below
  1860.                     carr = *wr;                    // carry to next pixel
  1861.                     *wr = diffr / 4;            // 2/8 to pixel below right
  1862.                     diffr = (diffr * 3)/8;    // 3/8 to pixel right;
  1863.                     diffg = curg - (lg * 256);
  1864.                     *wg++ = (diffg * 3)/8;
  1865.                     carg = *wg;
  1866.                     *wg = diffg / 4;
  1867.                     diffg = (diffg * 3)/8;
  1868.                     diffb = curb - (lb * 256);
  1869.                     *wb++ = (diffb * 3)/8;
  1870.                     carb = *wb;
  1871.                     *wb = diffb / 4;
  1872.                     diffb = (diffb * 3)/8;
  1873.                     if (index == 64) {
  1874.                         *old++ = (rr>>2) | 0x80;
  1875.                     }
  1876.                     else {
  1877.                         if (index == 65) {
  1878.                             *old++ = (gg>>2) | 0xc0;
  1879.                         }
  1880.                         else {
  1881.                             if (index == 66) {
  1882.                                 *old++ = (bb>>2) | 0x40;
  1883.                             }
  1884.                             else {
  1885.                                 *old++ = index;
  1886.                             }
  1887.                         }
  1888.                     }
  1889.                     r++;
  1890.                     g++;
  1891.                     b++;
  1892.                 }
  1893.             }
  1894.             c2p.bmap = (struct BitMap *)bitmap;
  1895.             c2p.startX = 0;
  1896.             c2p.startY = 0;
  1897.             c2p.width = width;
  1898.             c2p.height = height;
  1899.             c2p.chunkybuffer = red;
  1900.             ChunkyToPlanar(&c2p);
  1901.             AddMessageNo(MSG_SILBM);
  1902.             if (!NewBitMap) {
  1903.                 OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,8,camg,DIPF_IS_HAM,FileName),
  1904.                                      width,  height, width, height,
  1905.                                      palette, 64, 8,    /* colortable */
  1906.                                      mskNone, 0,    /* masking, transparent */
  1907.                                      NULL, NULL,     /* chunklists */
  1908.                                      (UBYTE *)FileName,8);
  1909.             }
  1910.             else {
  1911.                 OkFlag = TRUE;
  1912.             }
  1913.             // Close everything down cleanly
  1914.             FreeIFF(ilbm.ParseInfo.iff);
  1915.         }
  1916.         else {
  1917.             strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
  1918.             OkFlag = FALSE;
  1919.         }
  1920.         if (!NewBitMap) {
  1921.             MyFreeBitMap(bitmap,FileName);
  1922.         }
  1923.     }
  1924.     else {
  1925.         strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
  1926.         OkFlag = FALSE;
  1927.     }
  1928.     if (word) {
  1929.         FreeVec(word);
  1930.     }
  1931.     return OkFlag;
  1932. }
  1933.  
  1934. /* save 24
  1935.  * see Save24()
  1936.  */
  1937. static BOOL
  1938. Save24(const UBYTE *FileName,USHORT width,USHORT height,
  1939.                   UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg) {
  1940.     struct ILBMInfo     ilbm = {0};        // IFF stuff to save
  1941.     BOOL OkFlag;
  1942.     UBYTE *Planes[24]={0};
  1943.     struct MyBitMap *bitmap;
  1944.     int i;
  1945.     struct c2pStruct c2p;
  1946.  
  1947.     AddMessageNo(MSG_S24);
  1948.     // Set up BitMap
  1949.     if (bitmap = MyAllocBitMap(width,height,24,FileName)) {
  1950.         for (i=0; i<24; i++) {
  1951.             Planes[i] = bitmap->BitMap.Planes[i];
  1952.         }
  1953.         if (ilbm.ParseInfo.iff = AllocIFF()) {
  1954.             // i.e. 24 bit ILBM?
  1955.             // so convert chunky to planar
  1956.             bitmap->BitMap.Depth = 8;
  1957.             c2p.bmap = &(bitmap->BitMap);
  1958.             c2p.startX = 0;
  1959.             c2p.startY = 0;
  1960.             c2p.width = width;
  1961.             c2p.height = height;
  1962.             c2p.chunkybuffer = red;
  1963.             ChunkyToPlanar(&c2p);
  1964.             bitmap->BitMap.Planes[0] = Planes[8];
  1965.             bitmap->BitMap.Planes[1] = Planes[9];
  1966.             bitmap->BitMap.Planes[2] = Planes[10];
  1967.             bitmap->BitMap.Planes[3] = Planes[11];
  1968.             bitmap->BitMap.Planes[4] = Planes[12];
  1969.             bitmap->BitMap.Planes[5] = Planes[13];
  1970.             bitmap->BitMap.Planes[6] = Planes[14];
  1971.             bitmap->BitMap.Planes[7] = Planes[15];
  1972.             c2p.chunkybuffer = green;
  1973.             ChunkyToPlanar(&c2p);
  1974.             bitmap->BitMap.Planes[0] = Planes[16];
  1975.             bitmap->BitMap.Planes[1] = Planes[17];
  1976.             bitmap->BitMap.Planes[2] = Planes[18];
  1977.             bitmap->BitMap.Planes[3] = Planes[19];
  1978.             bitmap->BitMap.Planes[4] = Planes[20];
  1979.             bitmap->BitMap.Planes[5] = Planes[21];
  1980.             bitmap->BitMap.Planes[6] = Planes[22];
  1981.             bitmap->BitMap.Planes[7] = Planes[23];
  1982.             c2p.chunkybuffer = blue;
  1983.             ChunkyToPlanar(&c2p);
  1984.             InitBitMap((struct BitMap *)bitmap,24,width,height);
  1985.             for (i=0; i<24; i++) {
  1986.                 bitmap->BitMap.Planes[i] = Planes[i];
  1987.             }
  1988.             AddMessageNo(MSG_SILBM);
  1989.             OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,24,camg,0,FileName),
  1990.                                      width,  height, width, height,
  1991.                                      NULL, 0, 0,    /* colortable */
  1992.                                      mskNone, 0,    /* masking, transparent */
  1993.                                      NULL, NULL,     /* chunklists */
  1994.                                      (UBYTE *)FileName,24);
  1995.             // Close everything down cleanly
  1996.             FreeIFF(ilbm.ParseInfo.iff);
  1997.         }
  1998.         else {
  1999.             strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
  2000.             OkFlag = FALSE;
  2001.         }
  2002.         MyFreeBitMap(bitmap,FileName);
  2003.     }
  2004.     else {
  2005.         strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
  2006.         OkFlag = FALSE;
  2007.     }
  2008.     return OkFlag;
  2009. }
  2010.  
  2011. static BOOL
  2012. SavePPM(const UBYTE *FileName,USHORT width,USHORT height,
  2013.                   UBYTE *red, UBYTE *green, UBYTE *blue, UWORD jpeg) {
  2014.     int x,y;
  2015.     int i,j;
  2016.     UBYTE *arrayr,*arrayg,*arrayb;
  2017.     BPTR                fh;            // File handle for PPM
  2018.     BOOL OkFlag = TRUE;
  2019.     UBYTE buffer[32];
  2020.     char jpegbuf[120];
  2021.     char jpegpip[32];
  2022.     char jpegcom[256];
  2023.     char *jfilename;
  2024.  
  2025.     if (!jpeg) {
  2026.         AddMessageNo(MSG_SPPM);
  2027.         jfilename = FileName;
  2028.     }
  2029.     else {
  2030.         if (jpeg == 1) {
  2031.             AddMessageNo(MSG_SJPEG);
  2032.         }
  2033.         else {
  2034.             AddMessageNo(MSG_SPNG);
  2035.         }
  2036.         if (((jpeg == 1) && (GetVar("mpimage/cjpeg",jpegbuf,119,0) > 0)) ||
  2037.              ((jpeg == 2) && (GetVar("mpimage/pnmtopng",jpegbuf,119,0) > 0))) {
  2038.             if (fh = Open(FileName,MODE_NEWFILE)) {
  2039.                 Close(fh);
  2040.             }
  2041.             else {
  2042.                 strcpy(ErrorMessage,GetMg(MSG_ERR_OPENOUT));
  2043.                 return FALSE;
  2044.             }
  2045.             sprintf(jpegpip,"%s%ld","PIPE:",red);
  2046.             AddMessage(jpegpip);
  2047.             sprintf(jpegcom,jpegbuf,jpegpip,FileName);
  2048.             SystemTags(jpegcom,
  2049.                     SYS_Input,    0,
  2050.                     SYS_Output,    0,
  2051.                     SYS_Asynch,    TRUE,
  2052.                     NP_StackSize,    16000,
  2053.                     NP_Name,        (jpeg == 1) ? "MPImage CJPEG task" : "MPImage PNMTOPNG task",
  2054.                     TAG_END);
  2055.             jfilename = jpegpip;
  2056.             j = 0;
  2057.             for (i = 0;
  2058.                   (i < 20) && (!j);
  2059.                   ++i) {
  2060.                 BYTE pri;
  2061.                 // Try to write to file - if this works then wait again
  2062.                 pri = SetTaskPri(FindTask(0),21);
  2063.                 if (fh = Open(FileName,MODE_NEWFILE)) {
  2064.                     Close(fh);
  2065.                     if (jpeg == 1) {
  2066.                         AddMessageNo(MSG_WCJPEG);
  2067.                     }
  2068.                     else {
  2069.                         AddMessageNo(MSG_WPNMTOPNG);
  2070.                     }
  2071.                     Delay(50*1);
  2072.                 }
  2073.                 else {
  2074.                     j = 1;
  2075.                 }
  2076.                 SetTaskPri(FindTask(0),pri);
  2077.             }
  2078.             if (!j) {
  2079.                 if (jpeg == 1) {
  2080.                     strcpy(ErrorMessage,GetMg(MSG_ERR_CJPEG));
  2081.                 }
  2082.                 else {
  2083.                     strcpy(ErrorMessage,GetMg(MSG_ERR_PNMTOPNG));
  2084.                 }
  2085.                 return FALSE;
  2086.             }
  2087.         }
  2088.         else {
  2089.             if (jpeg == 1) {
  2090.                 strcpy(ErrorMessage,GetMg(MSG_ERR_GCJPEG));
  2091.             }
  2092.             else {
  2093.                 strcpy(ErrorMessage,GetMg(MSG_ERR_GPNMTOPNG));
  2094.             }
  2095.             return FALSE;
  2096.         }
  2097.     }
  2098.     if (fh = Open((UBYTE *)jfilename,MODE_NEWFILE)) {
  2099.         if ((red == green) && (red == blue)) {    // grey scale input
  2100.             AddMessageNo(MSG_SP5);
  2101.             sprintf(buffer,"P5\n%ld %ld\n255\n",width,height);
  2102.             FPuts(fh,buffer);
  2103.             if (FWrite(fh,red,width,height) != height) {
  2104.                 OkFlag = FALSE;
  2105.                 strcpy(ErrorMessage,GetMg(MSG_ERR_WRITE));
  2106.             }
  2107.         }
  2108.         else {
  2109.             AddMessageNo(MSG_SP6);
  2110.             sprintf(buffer,"P6\n%ld %ld\n255\n",width,height);
  2111.             FPuts(fh,buffer);
  2112.             arrayr=red;
  2113.             arrayg=green;
  2114.             arrayb=blue;
  2115.             SetMax(height);
  2116.             // loop thru lines
  2117.             for (y=0;
  2118.                   (y<height) && OkFlag;
  2119.                       y++) {
  2120.                 SetCur(y);
  2121.                 // Loop thru columns
  2122.                 for (x=0;
  2123.                       (x < width) && OkFlag;
  2124.                       x++) {
  2125.                     if (FPutC(fh,*arrayr++) == EOF) {
  2126.                         OkFlag = FALSE;
  2127.                     }
  2128.                     else {
  2129.                         if (FPutC(fh,*arrayg++) == EOF) {
  2130.                             OkFlag = FALSE;
  2131.                         }
  2132.                         else {
  2133.                             if (FPutC(fh,*arrayb++) == EOF) {
  2134.                                 OkFlag = FALSE;
  2135.                             }
  2136.                         }
  2137.                     }
  2138.                     if (!OkFlag) {
  2139.                         strcpy(ErrorMessage,GetMg(MSG_ERR_WRITE));
  2140.                     }
  2141.                 }
  2142.             }
  2143.         }
  2144.         if (!Close(fh)) {
  2145.             strcpy(ErrorMessage,GetMg(MSG_ERR_CLOSE));
  2146.             OkFlag = FALSE;
  2147.         }
  2148.     }
  2149.     else {
  2150.         strcpy(ErrorMessage,GetMg(MSG_ERR_OPENOUT));
  2151.         OkFlag = FALSE;
  2152.     }
  2153.     return OkFlag;
  2154. }
  2155.  
  2156. static BOOL
  2157. SaveColour(const UBYTE *FileName,USHORT width,USHORT height,
  2158.                   UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg, ULONG numcols, struct BitMap *NewBitMap) {
  2159.     UBYTE *r,*g,*b,*p;
  2160.     UBYTE rr,gg,bb;
  2161.     UBYTE *old;
  2162.     UWORD x,y;
  2163.     ULONG maxdiff;
  2164.     ULONG diff;
  2165.     LONG t;
  2166.     UWORD k;
  2167.     UWORD index=0;
  2168.     BOOL OkFlag=FALSE;
  2169.     struct ILBMInfo ilbm = {0};
  2170.     struct MyBitMap *bitmap;
  2171.     struct c2pStruct c2p;
  2172.     int *word,*wr,*wg,*wb;
  2173.     int diffr,curr,newr,carr;
  2174.     int diffg,curg,newg,carg;
  2175.     int diffb,curb,newb,carb;
  2176.     int Depth;
  2177.  
  2178.     AddMessageNo(MSG_SCOL);
  2179.     bitmap = (struct MyBitMap *)NewBitMap;
  2180.     if (numcols > 128) {
  2181.         Depth = 8;
  2182.     }
  2183.     else {
  2184.         if (numcols > 64) {
  2185.             Depth = 7;
  2186.         }
  2187.         else {
  2188.             if (numcols > 32) {
  2189.                 Depth = 6;
  2190.             }
  2191.             else {
  2192.                 if (numcols > 16) {
  2193.                     Depth = 5;
  2194.                 }
  2195.                 else {
  2196.                     if (numcols > 8) {
  2197.                         Depth = 4;
  2198.                     }
  2199.                     else {
  2200.                         if (numcols > 4) {
  2201.                             Depth = 3;
  2202.                         }
  2203.                         else {
  2204.                             if (numcols > 2) {
  2205.                                 Depth = 2;
  2206.                             }
  2207.                             else {
  2208.                                 Depth = 1;
  2209.                             }
  2210.                         }
  2211.                     }
  2212.                 }
  2213.             }
  2214.         }
  2215.     }
  2216.     if ((word = AllocVec((sizeof(int))*(width+1)*3,MEMF_CLEAR)) &&
  2217.          ((NewBitMap) || (bitmap = MyAllocBitMap(width,height,Depth,FileName)))) {
  2218.         if (ilbm.ParseInfo.iff = AllocIFF()) {
  2219.             r = red;
  2220.             g = green;
  2221.             b = blue;
  2222.             old = red;
  2223.             AddMessageNo(MSG_REMAP);
  2224.             SetMax(height);
  2225.             for (y=0;
  2226.                   y<height;
  2227.                   y++) {
  2228.                 SetCur(y);
  2229.                 wr = word;    // Carrys from previous row
  2230.                 diffr = 0;    // Carry from last column
  2231.                 carr = *wr;    // Carry from last row
  2232.                 wg = word+(width+1);
  2233.                 diffg = 0;
  2234.                 carg = *wg;
  2235.                 wb = word+(2*(width+1));
  2236.                 diffb = 0;
  2237.                 carb = *wb;
  2238.                 for (x=0;
  2239.                       x < width;
  2240.                       x++) {
  2241.                     curr = ((int)*r * 256) + diffr + carr;
  2242.                     newr = curr / 256;
  2243.                     if (newr > 255) {
  2244.                         rr = 255;
  2245.                     }
  2246.                     else {
  2247.                         if (newr < 0) {
  2248.                             rr = 0;
  2249.                         }
  2250.                         else {
  2251.                             rr = newr;
  2252.                         }
  2253.                     }
  2254.                     curg = ((int)*g * 256) + diffg + carg;
  2255.                     newg = curg / 256;
  2256.                     if (newg > 255) {
  2257.                         gg = 255;
  2258.                     }
  2259.                     else {
  2260.                         if (newg < 0) {
  2261.                             gg = 0;
  2262.                         }
  2263.                         else {
  2264.                             gg = newg;
  2265.                         }
  2266.                     }
  2267.                     curb = ((int)*b * 256) + diffb + carb;
  2268.                     newb = curb / 256;
  2269.                     if (newb > 255) {
  2270.                         bb = 255;
  2271.                     }
  2272.                     else {
  2273.                         if (newb < 0) {
  2274.                             bb = 0;
  2275.                         }
  2276.                         else {
  2277.                             bb = newb;
  2278.                         }
  2279.                     }
  2280.                     // Find closest color
  2281.                     maxdiff = 0x7FFFFFFF;
  2282.                     p = &(MyPalette[0][0]);
  2283.                     for (k = 0;
  2284.                           (k < numcols) && maxdiff;
  2285.                           ++k) {
  2286.                         t = (int)rr - (int)*p++;
  2287.                         diff = t*t * 2;
  2288.                         if (diff < maxdiff) {
  2289.                             t = (int)gg - (int)*p++;
  2290.                             diff += t*t * 4;
  2291.                             if (diff < maxdiff) {
  2292.                                 t = (int)bb - (int)*p++;
  2293.                                 diff += t*t;
  2294.                                 if (diff < maxdiff) {
  2295.                                     maxdiff = diff;
  2296.                                     index = k;
  2297.                                 }
  2298.                             }
  2299.                             else {
  2300.                                 ++p;
  2301.                             }
  2302.                         }
  2303.                         else {
  2304.                             ++p;
  2305.                             ++p;
  2306.                         }
  2307.                     }
  2308.                     // FS dither
  2309.                     diffr = curr - (MyPalette[index][0] * 256);
  2310.                     *wr++ = (diffr * 3)/8;    //    3/8 to pixel below
  2311.                     carr = *wr;                    // carry to next pixel
  2312.                     *wr = diffr / 4;            // 2/8 to pixel below right
  2313.                     diffr = (diffr * 3)/8;    // 3/8 to pixel right;
  2314.                     diffg = curg - (MyPalette[index][1] * 256);
  2315.                     *wg++ = (diffg * 3)/8;
  2316.                     carg = *wg;
  2317.                     *wg = diffg / 4;
  2318.                     diffg = (diffg * 3)/8;
  2319.                     diffb = curb - (MyPalette[index][2] * 256);
  2320.                     *wb++ = (diffb * 3)/8;
  2321.                     carb = *wb;
  2322.                     *wb = diffb / 4;
  2323.                     diffb = (diffb * 3)/8;
  2324.                     *old++ = index;
  2325.                     r++;
  2326.                     g++;
  2327.                     b++;
  2328.                 }
  2329.             }
  2330.             c2p.bmap = (struct BitMap *)bitmap;
  2331.             c2p.startX = 0;
  2332.             c2p.startY = 0;
  2333.             c2p.width = width;
  2334.             c2p.height = height;
  2335.             c2p.chunkybuffer = red;
  2336.             ChunkyToPlanar(&c2p);
  2337.             AddMessageNo(MSG_SILBM);
  2338.             if (!NewBitMap) {
  2339.                 OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap,GetMode(height,width,Depth,camg,0,FileName),
  2340.                                      width,  height, width, height,
  2341.                                      MyPalette, numcols, 8,    /* colortable */
  2342.                                      mskNone, 0,    /* masking, transparent */
  2343.                                      NULL, NULL,     /* chunklists */
  2344.                                      (UBYTE *)FileName,Depth);
  2345.             }
  2346.             else {
  2347.                 OkFlag = TRUE;
  2348.             }
  2349.             // Close everything down cleanly
  2350.             FreeIFF(ilbm.ParseInfo.iff);
  2351.         }
  2352.         else {
  2353.             strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
  2354.             OkFlag = FALSE;
  2355.         }
  2356.         if (!NewBitMap) {
  2357.             MyFreeBitMap(bitmap,FileName);
  2358.         }
  2359.     }
  2360.     else {
  2361.         strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
  2362.         OkFlag = FALSE;
  2363.     }
  2364.     if (word) {
  2365.         FreeVec(word);
  2366.     }
  2367.     return OkFlag;
  2368. }
  2369.  
  2370. static BOOL
  2371. SaveColour12(const UBYTE *FileName,USHORT width,USHORT height,
  2372.                   UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg, ULONG numcols, struct BitMap *NewBitMap) {
  2373.     UBYTE *r,*g,*b,*p;
  2374.     UBYTE rr,gg,bb;
  2375.     UBYTE *old;
  2376.     UWORD x,y;
  2377.     ULONG maxdiff;
  2378.     ULONG diff;
  2379.     LONG t;
  2380.     UWORD k;
  2381.     UWORD index=0;
  2382.     BOOL OkFlag=FALSE;
  2383.     struct ILBMInfo ilbm = {0};
  2384.     struct MyBitMap *bitmap;
  2385.     struct c2pStruct c2p;
  2386.     int *word = NULL,*wr,*wg,*wb;
  2387.     int diffr,curr,newr,carr;
  2388.     int diffg,curg,newg,carg;
  2389.     int diffb,curb,newb,carb;
  2390.     UBYTE *InvMap;
  2391.     int i,ir,ig,ib;
  2392.     int Depth;
  2393.  
  2394.     AddMessageNo(MSG_S12);
  2395.     bitmap = (struct MyBitMap *)NewBitMap;
  2396.     if (numcols > 128) {
  2397.         Depth = 8;
  2398.     }
  2399.     else {
  2400.         if (numcols > 64) {
  2401.             Depth = 7;
  2402.         }
  2403.         else {
  2404.             if (numcols > 32) {
  2405.                 Depth = 6;
  2406.             }
  2407.             else {
  2408.                 if (numcols > 16) {
  2409.                     Depth = 5;
  2410.                 }
  2411.                 else {
  2412.                     if (numcols > 8) {
  2413.                         Depth = 4;
  2414.                     }
  2415.                     else {
  2416.                         if (numcols > 4) {
  2417.                             Depth = 3;
  2418.                         }
  2419.                         else {
  2420.                             if (numcols > 2) {
  2421.                                 Depth = 2;
  2422.                             }
  2423.                             else {
  2424.                                 Depth = 1;
  2425.                             }
  2426.                         }
  2427.                     }
  2428.                 }
  2429.             }
  2430.         }
  2431.     }
  2432.  
  2433.     if ((InvMap = AllocVec(4906,MEMF_ANY)) &&
  2434.          (word = AllocVec((sizeof(int))*(width+1)*3,MEMF_CLEAR)) &&
  2435.          ((NewBitMap) || (bitmap = MyAllocBitMap(width,height,Depth,FileName)))) {
  2436.         if (ilbm.ParseInfo.iff = AllocIFF()) {
  2437.             AddMessageNo(MSG_BM);
  2438.             // Compute inverse color map
  2439.             for (i = 0; i < 4096; ++i) {
  2440.                 ir = RED6(i);
  2441.                 ig = GREEN6(i);
  2442.                 ib = BLUE6(i);
  2443.                 // Find closest color
  2444.                 maxdiff = 0x7FFFFFFF;
  2445.                 p = &(MyPalette[0][0]);
  2446.                 for (k = 0;
  2447.                       (k < numcols) && maxdiff;
  2448.                       ++k) {
  2449.                     t = ir - (int)*p++;
  2450.                     diff = t*t * 2;
  2451.                     if (diff < maxdiff) {
  2452.                         t = ig - (int)*p++;
  2453.                         diff += t*t * 4;
  2454.                         if (diff < maxdiff) {
  2455.                             t = ib - (int)*p++;
  2456.                             diff += t*t;
  2457.                             if (diff < maxdiff) {
  2458.                                 maxdiff = diff;
  2459.                                 index = k;
  2460.                             }
  2461.                         }
  2462.                         else {
  2463.                             ++p;
  2464.                         }
  2465.                     }
  2466.                     else {
  2467.                         ++p;
  2468.                         ++p;
  2469.                     }
  2470.                 }
  2471.                 InvMap[i] = index;
  2472.             }
  2473.             r = red;
  2474.             g = green;
  2475.             b = blue;
  2476.             old = red;
  2477.             AddMessageNo(MSG_REMAP);
  2478.             SetMax(height);
  2479.             for (y=0;
  2480.                   y<height;
  2481.                   y++) {
  2482.                 SetCur(y);
  2483.                 wr = word;    // Carrys from previous row
  2484.                 diffr = 0;    // Carry from last column
  2485.                 carr = *wr;    // Carry from last row
  2486.                 wg = word+(width+1);
  2487.                 diffg = 0;
  2488.                 carg = *wg;
  2489.                 wb = word+(2*(width+1));
  2490.                 diffb = 0;
  2491.                 carb = *wb;
  2492.                 for (x=0;
  2493.                       x < width;
  2494.                       x++) {
  2495.                     curr = ((int)*r * 256) + diffr + carr;
  2496.                     newr = curr / 256;
  2497.                     if (newr > 255) {
  2498.                         rr = 255;
  2499.                     }
  2500.                     else {
  2501.                         if (newr < 0) {
  2502.                             rr = 0;
  2503.                         }
  2504.                         else {
  2505.                             rr = newr;
  2506.                         }
  2507.                     }
  2508.                     curg = ((int)*g * 256) + diffg + carg;
  2509.                     newg = curg / 256;
  2510.                     if (newg > 255) {
  2511.                         gg = 255;
  2512.                     }
  2513.                     else {
  2514.                         if (newg < 0) {
  2515.                             gg = 0;
  2516.                         }
  2517.                         else {
  2518.                             gg = newg;
  2519.                         }
  2520.                     }
  2521.                     curb = ((int)*b * 256) + diffb + carb;
  2522.                     newb = curb / 256;
  2523.                     if (newb > 255) {
  2524.                         bb = 255;
  2525.                     }
  2526.                     else {
  2527.                         if (newb < 0) {
  2528.                             bb = 0;
  2529.                         }
  2530.                         else {
  2531.                             bb = newb;
  2532.                         }
  2533.                     }
  2534.                     // Find closest color
  2535.                     index = InvMap[RGB6(rr,gg,bb)];
  2536.                     // FS dither
  2537.                     diffr = curr - (MyPalette[index][0] * 256);
  2538.                     *wr++ = (diffr * 3)/8;    //    3/8 to pixel below
  2539.                     carr = *wr;                    // carry to next pixel
  2540.                     *wr = diffr / 4;            // 2/8 to pixel below right
  2541.                     diffr = (diffr * 3)/8;    // 3/8 to pixel right;
  2542.                     diffg = curg - (MyPalette[index][1] * 256);
  2543.                     *wg++ = (diffg * 3)/8;
  2544.                     carg = *wg;
  2545.                     *wg = diffg / 4;
  2546.                     diffg = (diffg * 3)/8;
  2547.                     diffb = curb - (MyPalette[index][2] * 256);
  2548.                     *wb++ = (diffb * 3)/8;
  2549.                     carb = *wb;
  2550.                     *wb = diffb / 4;
  2551.                     diffb = (diffb * 3)/8;
  2552.                     *old++ = index;
  2553.                     r++;
  2554.                     g++;
  2555.                     b++;
  2556.                 }
  2557.             }
  2558.             c2p.bmap = (struct BitMap *)bitmap;
  2559.             c2p.startX = 0;
  2560.             c2p.startY = 0;
  2561.             c2p.width = width;
  2562.             c2p.height = height;
  2563.             c2p.chunkybuffer = red;
  2564.             ChunkyToPlanar(&c2p);
  2565.             AddMessageNo(MSG_SILBM);
  2566.             if (!NewBitMap) {
  2567.                 OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,Depth,camg,0,FileName),
  2568.                                      width,  height, width, height,
  2569.                                      MyPalette, numcols, 8,    /* colortable */
  2570.                                      mskNone, 0,    /* masking, transparent */
  2571.                                      NULL, NULL,     /* chunklists */
  2572.                                      (UBYTE *)FileName,Depth);
  2573.             }
  2574.             else {
  2575.                 OkFlag = TRUE;
  2576.             }
  2577.             // Close everything down cleanly
  2578.             FreeIFF(ilbm.ParseInfo.iff);
  2579.         }
  2580.         else {
  2581.             strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
  2582.             OkFlag = FALSE;
  2583.         }
  2584.         if (!NewBitMap) {
  2585.             MyFreeBitMap(bitmap,FileName);
  2586.         }
  2587.     }
  2588.     else {
  2589.         strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
  2590.         OkFlag = FALSE;
  2591.     }
  2592.     if (word) {
  2593.         FreeVec(word);
  2594.     }
  2595.     if (InvMap) {
  2596.         FreeVec(InvMap);
  2597.     }
  2598.     return OkFlag;
  2599. }
  2600.  
  2601. static BOOL
  2602. SaveEHB(const UBYTE *FileName,USHORT width,USHORT height,
  2603.                   UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg, struct BitMap *NewBitMap) {
  2604.     UBYTE *r,*g,*b,*p;
  2605.     UBYTE rr,gg,bb;
  2606.     UBYTE *old;
  2607.     UWORD x,y;
  2608.     ULONG maxdiff;
  2609.     ULONG diff;
  2610.     LONG t;
  2611.     UWORD k;
  2612.     UWORD index=0;
  2613.     BOOL OkFlag=FALSE;
  2614.     struct ILBMInfo ilbm = {0};
  2615.     struct MyBitMap *bitmap;
  2616.     struct c2pStruct c2p;
  2617.     int *word = NULL,*wr,*wg,*wb;
  2618.     int diffr,curr,newr,carr;
  2619.     int diffg,curg,newg,carg;
  2620.     int diffb,curb,newb,carb;
  2621.     UBYTE *InvMap;
  2622.     int i,ir,ig,ib,j;
  2623.  
  2624.     AddMessageNo(MSG_SEHB);
  2625.     bitmap = (struct MyBitMap *)NewBitMap;
  2626.     for (i = 0; i < 32; ++i) {
  2627.         for (j = 0; j < 3; ++j) {
  2628.             MyPalette[i+32][j] = (MyPalette[i][j])>>1;
  2629.         }
  2630.     }
  2631.     if ((InvMap = AllocVec(4906,MEMF_ANY)) &&
  2632.          (word = AllocVec((sizeof(int))*(width+1)*3,MEMF_CLEAR)) &&
  2633.          ((NewBitMap) || (bitmap = MyAllocBitMap(width,height,6,FileName)))) {
  2634.         if (ilbm.ParseInfo.iff = AllocIFF()) {
  2635.             AddMessageNo(MSG_BM);
  2636.             // Compute inverse color map
  2637.             for (i = 0; i < 4096; ++i) {
  2638.                 ir = RED6(i);
  2639.                 ig = GREEN6(i);
  2640.                 ib = BLUE6(i);
  2641.                 // Find closest color
  2642.                 maxdiff = 0x7FFFFFFF;
  2643.                 p = &(MyPalette[0][0]);
  2644.                 for (k = 0;
  2645.                       (k < 64) && maxdiff;
  2646.                       ++k) {
  2647.                     t = ir - (int)*p++;
  2648.                     diff = t*t * 2;
  2649.                     if (diff < maxdiff) {
  2650.                         t = ig - (int)*p++;
  2651.                         diff += t*t * 4;
  2652.                         if (diff < maxdiff) {
  2653.                             t = ib - (int)*p++;
  2654.                             diff += t*t;
  2655.                             if (diff < maxdiff) {
  2656.                                 maxdiff = diff;
  2657.                                 index = k;
  2658.                             }
  2659.                         }
  2660.                         else {
  2661.                             ++p;
  2662.                         }
  2663.                     }
  2664.                     else {
  2665.                         ++p;
  2666.                         ++p;
  2667.                     }
  2668.                 }
  2669.                 InvMap[i] = index;
  2670.             }
  2671.             r = red;
  2672.             g = green;
  2673.             b = blue;
  2674.             old = red;
  2675.             AddMessageNo(MSG_REMAP);
  2676.             SetMax(height);
  2677.             for (y=0;
  2678.                   y<height;
  2679.                   y++) {
  2680.                 SetCur(y);
  2681.                 wr = word;    // Carrys from previous row
  2682.                 diffr = 0;    // Carry from last column
  2683.                 carr = *wr;    // Carry from last row
  2684.                 wg = word+(width+1);
  2685.                 diffg = 0;
  2686.                 carg = *wg;
  2687.                 wb = word+(2*(width+1));
  2688.                 diffb = 0;
  2689.                 carb = *wb;
  2690.                 for (x=0;
  2691.                       x < width;
  2692.                       x++) {
  2693.                     curr = ((int)*r * 256) + diffr + carr;
  2694.                     newr = curr / 256;
  2695.                     if (newr > 255) {
  2696.                         rr = 255;
  2697.                     }
  2698.                     else {
  2699.                         if (newr < 0) {
  2700.                             rr = 0;
  2701.                         }
  2702.                         else {
  2703.                             rr = newr;
  2704.                         }
  2705.                     }
  2706.                     curg = ((int)*g * 256) + diffg + carg;
  2707.                     newg = curg / 256;
  2708.                     if (newg > 255) {
  2709.                         gg = 255;
  2710.                     }
  2711.                     else {
  2712.                         if (newg < 0) {
  2713.                             gg = 0;
  2714.                         }
  2715.                         else {
  2716.                             gg = newg;
  2717.                         }
  2718.                     }
  2719.                     curb = ((int)*b * 256) + diffb + carb;
  2720.                     newb = curb / 256;
  2721.                     if (newb > 255) {
  2722.                         bb = 255;
  2723.                     }
  2724.                     else {
  2725.                         if (newb < 0) {
  2726.                             bb = 0;
  2727.                         }
  2728.                         else {
  2729.                             bb = newb;
  2730.                         }
  2731.                     }
  2732.                     // Find closest color
  2733.                     index = InvMap[RGB6(rr,gg,bb)];
  2734.                     // FS dither
  2735.                     diffr = curr - (MyPalette[index][0] * 256);
  2736.                     *wr++ = (diffr * 3)/8;    //    3/8 to pixel below
  2737.                     carr = *wr;                    // carry to next pixel
  2738.                     *wr = diffr / 4;            // 2/8 to pixel below right
  2739.                     diffr = (diffr * 3)/8;    // 3/8 to pixel right;
  2740.                     diffg = curg - (MyPalette[index][1] * 256);
  2741.                     *wg++ = (diffg * 3)/8;
  2742.                     carg = *wg;
  2743.                     *wg = diffg / 4;
  2744.                     diffg = (diffg * 3)/8;
  2745.                     diffb = curb - (MyPalette[index][2] * 256);
  2746.                     *wb++ = (diffb * 3)/8;
  2747.                     carb = *wb;
  2748.                     *wb = diffb / 4;
  2749.                     diffb = (diffb * 3)/8;
  2750.                     *old++ = index;
  2751.                     r++;
  2752.                     g++;
  2753.                     b++;
  2754.                 }
  2755.             }
  2756.             c2p.bmap = (struct BitMap *)bitmap;
  2757.             c2p.startX = 0;
  2758.             c2p.startY = 0;
  2759.             c2p.width = width;
  2760.             c2p.height = height;
  2761.             c2p.chunkybuffer = red;
  2762.             ChunkyToPlanar(&c2p);
  2763.             AddMessageNo(MSG_SILBM);
  2764.             if (!NewBitMap) {
  2765.                 OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,6,camg,DIPF_IS_EXTRAHALFBRITE,FileName),
  2766.                                      width,  height, width, height,
  2767.                                      MyPalette, 32, 8,    /* colortable */
  2768.                                      mskNone, 0,    /* masking, transparent */
  2769.                                      NULL, NULL,     /* chunklists */
  2770.                                      (UBYTE *)FileName,6);
  2771.             }
  2772.             else {
  2773.                 OkFlag = TRUE;
  2774.             }
  2775.             // Close everything down cleanly
  2776.             FreeIFF(ilbm.ParseInfo.iff);
  2777.         }
  2778.         else {
  2779.             strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
  2780.             OkFlag = FALSE;
  2781.         }
  2782.         if (!NewBitMap) {
  2783.             MyFreeBitMap(bitmap,FileName);
  2784.         }
  2785.     }
  2786.     else {
  2787.         strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
  2788.         OkFlag = FALSE;
  2789.     }
  2790.     if (word) {
  2791.         FreeVec(word);
  2792.     }
  2793.     if (InvMap) {
  2794.         FreeVec(InvMap);
  2795.     }
  2796.     return OkFlag;
  2797. }
  2798.  
  2799. // Note returns 0 for success!
  2800. static LONG
  2801. mysaveilbm(struct ILBMInfo *ilbm,
  2802.         struct BitMap *bitmap, ULONG modeid,
  2803.         WORD width, WORD height, WORD pagewidth, WORD pageheight,
  2804.         UBYTE col[][3], UWORD count, UWORD bitspergun,
  2805.                 WORD masking, WORD transparentColor,
  2806.         struct Chunk *chunklist1, struct Chunk *chunklist2,
  2807.         UBYTE *filename, int Depth) {
  2808.     if (filename && *filename) {
  2809.         return saveilbm(ilbm,bitmap,modeid,width,height,pagewidth,pageheight,col,count,bitspergun,
  2810.                     masking,transparentColor,chunklist1,chunklist2,filename);
  2811.     }
  2812.     else {
  2813.         struct Screen* Screen;
  2814.         struct Rectangle Rectangle;
  2815.         struct Window *Window;
  2816.         int l,temp;
  2817.         int i;
  2818.         struct Message *msg;
  2819.         ULONG error;
  2820.         LONG okflag=1;
  2821.         AddMessageNo(MSG_DISPLAY);
  2822.         if (QueryOverscan(modeid, &Rectangle, OSCAN_MAX)) {
  2823.             if ((temp = (Rectangle.MaxX - Rectangle.MinX + 1)) > width) {
  2824.                 l = (temp-width)/2 + Rectangle.MinX;
  2825.                 Rectangle.MinX = l;
  2826.                 Rectangle.MaxX = l + width - 1;
  2827.             }
  2828.             else {
  2829.                 l = Rectangle.MinX;
  2830.             }
  2831.             if (Screen = OpenScreenTags(NULL,
  2832.                             SA_Left,            l,
  2833.                             SA_Top,            Rectangle.MinY,
  2834.                             SA_Width,        width,
  2835.                             SA_Height,        height,
  2836.                             SA_Depth,        Depth,
  2837.                             SA_ShowTitle,    FALSE,
  2838.                             SA_Quiet,        TRUE,
  2839.                             SA_Type,            CUSTOMSCREEN,
  2840.                             SA_DisplayID,    modeid,
  2841.                             SA_DClip,        &Rectangle,
  2842.                             SA_AutoScroll,    TRUE,
  2843.                             SA_ErrorCode,    &error,
  2844.                             SA_BitMap,        bitmap,
  2845. //                            SA_BackFill,    LAYERS_NOBACKFILL,
  2846.                             TAG_END)) {
  2847.                 if (8 == bitspergun) {
  2848.                     for (i = 0; i < count; ++i) {
  2849.                         SetRGB32(&(Screen->ViewPort),i,(col[i][0])<<24,(col[i][1])<<24,(col[i][2])<<24);
  2850.                     }
  2851.                 }
  2852.                 else {
  2853.                     LoadRGB4(&(Screen->ViewPort),(UWORD *)col,count);
  2854.                 }
  2855.                 if (Window = OpenWindowTags(NULL,
  2856.                                 WA_Left,                0,
  2857.                                 WA_Top,                Screen->BarHeight+1,
  2858.                                 WA_Width,            width,
  2859.                                 WA_Height,            height - Screen->BarHeight - 1,
  2860.                                 WA_IDCMP,            IDCMP_VANILLAKEY,
  2861.                                 WA_CustomScreen,    Screen,
  2862.                                 WA_Backdrop,        TRUE,
  2863.                                 WA_Borderless,        TRUE,
  2864.                                 WA_NoCareRefresh,    TRUE,
  2865.                                 WA_Activate,        TRUE,
  2866.                                 WA_RMBTrap,            TRUE,
  2867.                                 WA_BackFill,        LAYERS_NOBACKFILL,
  2868.                                 TAG_END)) {
  2869.                     AddMessageNo(MSG_WAITKEY);
  2870.                     WaitPort(Window->UserPort);
  2871.                     while (msg = GetMsg(Window->UserPort)) {
  2872.                         ReplyMsg(msg);
  2873.                     }
  2874.                     okflag = 0;
  2875.                     CloseWindow(Window);
  2876.                 }
  2877.                 else {
  2878.                     strcpy(ErrorMessage,GetMg(MSG_ERR_WINDOW));
  2879.                 }
  2880.                 CloseScreen(Screen);
  2881.             }
  2882.             else {
  2883.                 strcpy(ErrorMessage,GetMg(MSG_ERR_SCREEN));
  2884.                 switch(error) {
  2885.                 case OSERR_NOMONITOR:
  2886.                     strcat(ErrorMessage,GetMg(MSG_ERR_NOMON));
  2887.                     break;
  2888.                 case OSERR_NOCHIPS:
  2889.                     strcat(ErrorMessage,GetMg(MSG_ERR_OLDCHIP));
  2890.                     break;
  2891.                 case OSERR_NOMEM:
  2892.                     strcat(ErrorMessage,GetMg(MSG_ERR_NOMEM));
  2893.                     break;
  2894.                 case OSERR_NOCHIPMEM:
  2895.                     strcat(ErrorMessage,GetMg(MSG_ERR_NOCHIP));
  2896.                     break;
  2897.                 case OSERR_UNKNOWNMODE:
  2898.                     strcat(ErrorMessage,GetMg(MSG_ERR_NOMODE));
  2899.                     break;
  2900.                 case OSERR_TOODEEP:
  2901.                     strcat(ErrorMessage,GetMg(MSG_ERR_DEEP));
  2902.                     break;
  2903.                 default:
  2904.                     strcat(ErrorMessage,GetMg(MSG_ERR_UNK));
  2905.                     break;
  2906.                 }
  2907.             }
  2908.         }
  2909.         else {
  2910.             strcpy(ErrorMessage,GetMg(MSG_ERR_QOS));
  2911.         }
  2912.         return okflag;
  2913.     }
  2914. }
  2915.  
  2916. static BOOL SaveDCTV(const UBYTE *FileName,USHORT width,USHORT height,
  2917.                   UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg,BOOL dctv4, struct BitMap *NewBitMap) {
  2918.     int i;
  2919.     BOOL OkFlag=FALSE;
  2920.     struct ILBMInfo ilbm = {0};
  2921.     struct MyBitMap *bitmap;
  2922.     int Depth;
  2923.     struct DCTVCvtHandle *chandle;
  2924.     ULONG newcamg;
  2925.  
  2926.     bitmap = (struct MyBitMap *)NewBitMap;
  2927.     if (dctv4) {
  2928.         AddMessageNo(MSG_SDCTV4);
  2929.     }
  2930.     else {
  2931.         AddMessageNo(MSG_SDCTV3);
  2932.     }
  2933.     if (dctv4) {
  2934.         Depth = 4;
  2935.     }
  2936.     else {
  2937.         Depth = 3;
  2938.     }
  2939.     if (height > 300) {
  2940.         newcamg = HIRES|LACE;
  2941.     }
  2942.     else {
  2943.         newcamg = HIRES;
  2944.     }
  2945.     if (DCTVBase) {
  2946.         if ((NewBitMap) || (bitmap = MyAllocBitMap(width,height,Depth,FileName))) {
  2947.             if (ilbm.ParseInfo.iff = AllocIFF()) {
  2948.                 if (chandle = AllocDCTVCvtTags(bitmap,
  2949.                                                     DCTVCVTA_Type, DCTVCVTT_RGBtoDCTV,
  2950.                                                     DCTVCVTA_Flags,((newcamg&LACE)?DCTVCVTF_Lace:0)|
  2951.                                                                         DCTVCVTF_Filter|
  2952.                                                                         DCTVCVTF_CustomRGBBuf,
  2953.                                                     TAG_END)) {
  2954.                     chandle->Red = red;
  2955.                     chandle->Green = green;
  2956.                     chandle->Blue = blue;
  2957.                     // Convert each line
  2958.                     SetMax(chandle->Height);
  2959.                     while (chandle->DstLineNum < chandle->Height) {
  2960.                         i = chandle->SrcLineNum;
  2961.                         SetCur(i);
  2962.                         CvtDCTVLine(chandle);
  2963.                         if (i != chandle->SrcLineNum) {
  2964.                             chandle->Red += width;
  2965.                             chandle->Green += width;
  2966.                             chandle->Blue += width;
  2967.                         }
  2968.                     }
  2969.                     AddMessageNo(MSG_SILBM);
  2970.                     if (!NewBitMap) {
  2971.                         OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap,newcamg,
  2972.                                              width,  height, width, height,
  2973.                                              (UBYTE (*)[3])(chandle->ColorTable), dctv4?16:8, 4,    /* colortable */
  2974.                                              mskNone, 0,    /* masking, transparent */
  2975.                                              NULL, NULL,     /* chunklists */
  2976.                                              (UBYTE *)FileName,Depth);
  2977.                     }
  2978.                     else {
  2979.                         OkFlag = TRUE;
  2980.                     }
  2981.                     // Free DCTV stuff
  2982.                     FreeDCTVCvt(chandle);
  2983.                 }
  2984.                 else {
  2985.                     strcpy(ErrorMessage,GetMg(MSG_ERR_DCTVBUF));
  2986.                     OkFlag = FALSE;
  2987.                 }
  2988.                 // Close everything down cleanly
  2989.                 FreeIFF(ilbm.ParseInfo.iff);
  2990.             }
  2991.             else {
  2992.                 strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
  2993.                 OkFlag = FALSE;
  2994.             }
  2995.             if (!NewBitMap) {
  2996.                 MyFreeBitMap(bitmap,FileName);
  2997.             }
  2998.         }
  2999.         else {
  3000.             strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
  3001.             OkFlag = FALSE;
  3002.         }
  3003.     }
  3004.     else {
  3005.         strcpy(ErrorMessage,GetMg(MSG_ERR_DCTVL));
  3006.         OkFlag = FALSE;
  3007.     }
  3008.     return OkFlag;
  3009. }
  3010.